【问题标题】:How to redirect multiprocessing pool function如何重定向多处理池功能
【发布时间】:2018-01-11 23:25:07
【问题描述】:

我创建了一个 tkinter 文本小部件,我想将 sys.stdout 重定向到文本小部件。我部分实现了这个功能,但我遇到了多处理问题。

以下是你可以玩的python 3玩具,

import sys
import tkinter as tk
from multiprocessing import Pool

root = tk.Tk()
root.geometry('600x400+30+30')

textArea = tk.Text(root, bg='gray', width=70, height=20)
textArea.pack()
tk.Button(root, text='click me', command=lambda: print('Dont touch\n me!')).pack()

class redirectStd():
    def __init__(self, textWidget):
        self.textBoard = textWidget
        self.flush = sys.stdout.flush
    def write(self, msg):
        self.textBoard.insert('end', msg)

sys.stdout = redirectStd(textArea)
sys.stderr = redirectStd(textArea)

def f(x):
    print('calculate:', x, '** 2')
    return x ** 2

def testParallel():
    print('start testing')
    with Pool(processes=2) as p:
        res = p.map(f, [1, 4, 0, 7, 3, 5])
        print(res)

tk.Button(root, text='test multiprocessing', command=testParallel).pack()

root.mainloop()

这将正确运行。但是,def f(x) 中的打印不会在文本小部件中打印任何内容。

如果在class redirectStd 块中注释self.flush = sys.stdout.flush,将导致错误提示flush undefined in redirectStd。在这个阶段,我还没有弄清楚如何为 redirectStd 定义一个 flush 方法。完整的错误信息是

start testing
Exception in Tkinter callback
Traceback (most recent call last):
  File "/Users/zsf/miniconda3/lib/python3.6/tkinter/__init__.py", line 1699, in __call__
    return self.func(*args)
  File "test.py", line 28, in testParallel
    with Pool(processes=2) as p:
  File "/Users/zsf/miniconda3/lib/python3.6/multiprocessing/context.py", line 119, in Pool
    context=self.get_context())
  File "/Users/zsf/miniconda3/lib/python3.6/multiprocessing/pool.py", line 168, in __init__
    self._repopulate_pool()
  File "/Users/zsf/miniconda3/lib/python3.6/multiprocessing/pool.py", line 233, in _repopulate_pool
    w.start()
  File "/Users/zsf/miniconda3/lib/python3.6/multiprocessing/process.py", line 105, in start
    self._popen = self._Popen(self)
  File "/Users/zsf/miniconda3/lib/python3.6/multiprocessing/context.py", line 277, in _Popen
    return Popen(process_obj)
  File "/Users/zsf/miniconda3/lib/python3.6/multiprocessing/popen_fork.py", line 17, in __init__
    sys.stdout.flush()
AttributeError: 'redirectStd' object has no attribute 'flush'

任何人都可以为此提供解决方案的提示吗?谢谢!

【问题讨论】:

  • 重新考虑您的方法,使用一些 IPC 而不是重定向。你的基本问题是f 是一个单独的进程,有他自己的`Stdout。

标签: python tkinter


【解决方案1】:

我认为您使用多线程的方式可能有问题,请查看以下文档

https://docs.python.org/2/library/multiprocessing.html https://docs.python.org/2/library/multiprocessing.html#multiprocessing-programming

我以稍微不同的方式解决了您的问题,希望对您有所帮助

import sys
import tkinter as tk
from multiprocessing import Pool


class redirectStd():
    def __init__(self, textWidget):
    self.textBoard = textWidget
    #self.flush = sys.stdout.flush
def write(self, msg):
    self.textBoard.insert('end', msg)

def f(x):
    print('calculate:', x, '** 2')
    return x ** 2

if __name__ == '__main__':

    root = tk.Tk()
    root.geometry('600x400+30+30')

    textArea = tk.Text(root, bg='gray', width=70, height=20)
    textArea.pack()
    tk.Button(root, text='click me', command=lambda: print('Dont touch\n me!')).pack()

    sys.stdout = redirectStd(textArea)
    sys.stderr = redirectStd(textArea)

    def testParallel():
        p = Pool(5)
        print(p.map(f, [10, 2, 3]))

    tk.Button(root, text='test multiprocessing', command=testParallel).pack()

    root.mainloop()

【讨论】:

  • 感谢您的解决方案。它仍然会导致该错误。我必须取消注释 #self.flush = sys.stdout.flush 才能使其正常运行。但是,print('calculate: ', x, '** 2') 什么也不打印。你有什么进一步的建议吗?顺便说一句,我在 macOS 10.12.6 上测试了这个
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-07
相关资源
最近更新 更多