【问题标题】:Supressing stdout in particular process在特定进程中抑制标准输出
【发布时间】:2020-05-28 10:13:11
【问题描述】:

我有一个执行两个主要任务的 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() 语句,因为程序的另一个例程在主进程上调用该函数并且它需要那些打印语句。

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

非常感谢!

【问题讨论】:

    标签: python stdout suppressmessage


    【解决方案1】:

    我试过通过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 对象。

    【讨论】:

    • 谢谢! os.fork 的解释正是我想要的。
    【解决方案2】:

    你必须在 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?

    【讨论】:

    • 这似乎行得通。虽然不需要该对象,但如果您执行sys.stdout = None,它的效果也一样好,但是主进程中的sys.stdout = something 如何更改其所有子进程STDOUT(这很好,因为它应该像那样工作),但是修改其 STDOUT 的子进程不会更改其他进程的 STDOUT(这也很好,但每个 sys.stdout 都指向同一个对象!)。 multiprocessing 模块是否在做这些小改动?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-18
    • 2012-08-11
    • 2014-03-30
    • 1970-01-01
    • 2016-11-01
    相关资源
    最近更新 更多