在特定过程中抑制标准输出
Supressing stdout in particular process
我有一个 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()
语句,因为程序的另一个例程在主进程上调用该函数它需要那些打印语句。
我还注意到我可以使用一个布尔标志来指示是否应该执行打印,但我希望有人能给我一个更好的方法。
非常感谢!
你必须在 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")
创意来源:How to redirect stdout to both file and console with scripting?
I've tried to change it through sys.stdout, but it affects every single process and the main process (every instance of the program points to the same object)
您在此处提供的解决方案确实有效。试试 运行 这个简单的例子:
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
对象。
我有一个 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()
语句,因为程序的另一个例程在主进程上调用该函数它需要那些打印语句。
我还注意到我可以使用一个布尔标志来指示是否应该执行打印,但我希望有人能给我一个更好的方法。
非常感谢!
你必须在 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")
创意来源:How to redirect stdout to both file and console with scripting?
I've tried to change it through sys.stdout, but it affects every single process and the main process (every instance of the program points to the same object)
您在此处提供的解决方案确实有效。试试 运行 这个简单的例子:
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
对象。