Подавление стандартного вывода в конкретном процессе - PullRequest
0 голосов
/ 28 мая 2020

У меня есть сценарий Python, который выполняет две основные задачи:

  • Выполнение кода из самого сценария
  • Запуск фонового процесса с помощью multiprocessing.Process(target=...)

Мой вопрос: есть ли способ отключить stdout из этого конкретного процесса, не затрагивая основной процесс? Я пытался изменить его через sys.stdout, но это влияет на каждый процесс и основной процесс (каждый экземпляр программы указывает на один и тот же объект):

>>> import multiprocessing
>>> import sys
>>> def a():
...     print('{} - {}'.format(sys.stdout, id(sys.stdout)))
... 
>>> for i in range(5):
...     multiprocessing.Process(target=a).start()
... 
<_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'> - 140230387621232
<_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'> - 140230387621232
<_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'> - 140230387621232
<_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'> - 140230387621232
>>> <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'> - 140230387621232

>>> a()
<_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'> - 140230387621232

Невозможно удалить все print() операторы из функции, выполняемой процессом, поскольку другая подпрограмма программы вызывает эту функцию в основном процессе и ей нужны эти операторы печати.

Я также заметил, что могу использовать логический флаг, чтобы указать, следует ли выполнять печать, но я надеялся, что кто-нибудь сможет предложить мне лучший подход.

Большое спасибо !

Ответы [ 2 ]

1 голос
/ 05 июня 2020

Я пытался изменить его через sys.stdout, но это влияет на каждый процесс и основной процесс (каждый экземпляр программы указывает на один и тот же объект)

предложенное вами решение действительно работает. Попробуйте запустить этот простой пример:

def a(no_stdout):
    if no_stdout:
        sys.stdout = None
    print(id(sys.stdout))

multiprocessing.Process(target=a, args=(False,)).start() # Outputs the id
multiprocessing.Process(target=a, args=(True,)).start()  # Outputs nothing

Причина, по которой все процессы в вашем примере печатают одно и то же id, заключается в том, что multiprocessing.Process использует os.fork на вашей платформе. При разветвлении вся память процесса остается идентичной (и даже остается по одному и тому же физическому адресу, пока она не будет изменена дочерним процессом). Таким образом, хотя адреса одинаковы, каждый из них относится к разному sys.stdout объекту в памяти каждого из процессов.

0 голосов
/ 01 июня 2020

Это нужно делать внутри процесса, после fork. Это немного грубо, но, похоже, работает:

#!/usr/bin/env python3

import multiprocessing
import sys

class SinkLogger(object):
    def __init__(self):
        pass

    def write(self, message):
        pass

    def flush(self):
        pass  

def a(i):
    if (i % 2 == 1):
        sys.stdout = SinkLogger()
    print('{} - {} - {}'.format(i, sys.stdout, id(sys.stdout)))

for i in range(5):
    multiprocessing.Process(target=a, args=(i,)).start()

print("done")

Источник идеи: Как перенаправить stdout как в файл, так и в консоль с помощью сценариев?

...