在特定进程中抑制 stdout

Supressing stdout in particular process

提问人:Cblopez 提问时间:5/28/2020 最后编辑:kadambCblopez 更新时间:6/5/2020 访问量:109

问:

我有一个执行两个主要任务的 Python 脚本:

  • 从脚本本身执行代码
  • 启动后台进程multiprocessing.Process(target=...)

我的问题是:有没有办法在不影响主进程的情况下将该特定进程静音?我试图通过 更改它,但它会影响每个进程和主进程(程序的每个实例都指向同一个对象):stdoutsys.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() 语句,因为程序的另一个例程在主进程上调用该函数,并且它需要这些 print 语句。

我还注意到,我可以使用布尔标志来指示是否应该执行打印,但我希望有人能给我一个更好的方法。

谢谢!

python stdout 抑制消息

评论


答:

0赞 teki 6/1/2020 #1

你必须在分叉之后在进程内完成。这有点粗糙,但似乎正在起作用:

#!/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 重定向到文件和控制台?

评论

0赞 Cblopez 6/1/2020
这似乎奏效了。虽然不需要该对象,但如果您这样做,它工作得很好,但是主进程如何更改其所有子进程 STDOUT(这很好,因为它应该像那样工作),但是修改他的 STDOUT 的子进程不会更改其他进程 STDOUT(这也很好,但每个都指向同一个对象!模块是否在桌子底下进行这些小更改?sys.stdout = Nonesys.stdout = somethingsys.stdoutmultiprocessing
2赞 kmaork 6/5/2020 #2

我试图通过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

示例中的所有进程都打印相同的原因是在您的平台上使用。分叉时,所有进程的内存都保持相同(甚至保持在同一物理地址,直到它被子进程修改)。因此,尽管地址相同,但它们在每个进程的内存中都引用了不同的对象。idmultiprocessing.Processos.forksys.stdout

评论

0赞 Cblopez 6/5/2020
谢谢!这个解释就是我一直在寻找的。os.fork