且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何将python multiprocessing Process输出发送到Tkinter GUI

更新时间:2023-11-27 14:43:40

您可以将stdout/stderr重定向到myfunc()中的StringIO,然后将写入该StringIO的所有内容发送回父级(由unutbu建议).查看我对这个问题的答案一种实现重定向的方式.

You could redirect stdout/stderr to a StringIO in myfunc(), then send whatever gets written into that StringIO back to the parent (as suggested by unutbu). See my answer to this question for one way of doing this redirection.

由于该示例的功能超出了您的需求,因此此版本更符合您的既定目标:

Since that example does a bit more than you need, here's a version that's more aligned with your stated goals:

#!/usr/bin/env python
import sys
from cStringIO import StringIO
from code import InteractiveConsole
from contextlib import contextmanager
from multiprocessing import Process, Pipe

@contextmanager
def std_redirector(stdin=sys.stdin, stdout=sys.stdin, stderr=sys.stderr):
    tmp_fds = stdin, stdout, stderr
    orig_fds = sys.stdin, sys.stdout, sys.stderr
    sys.stdin, sys.stdout, sys.stderr = tmp_fds
    yield
    sys.stdin, sys.stdout, sys.stderr = orig_fds

class Interpreter(InteractiveConsole):
    def __init__(self, locals=None):
        InteractiveConsole.__init__(self, locals=locals)
        self.output = StringIO()
        self.output = StringIO()

    def push(self, command):
        self.output.reset()
        self.output.truncate()
        with std_redirector(stdout=self.output, stderr=self.output):
            try:
                more = InteractiveConsole.push(self, command)
                result = self.output.getvalue()
            except (SyntaxError, OverflowError):
                pass
            return more, result

def myfunc(conn, commands):
    output = StringIO()
    py = Interpreter()
    results = ""

    for line in commands.split('\n'):
        if line and len(line) > 0:
            more, result = py.push(line + '\n')
            if result and len(result) > 0:
                results += result

    conn.send(results)
    conn.close()

if __name__ == '__main__':
    parent_conn, child_conn = Pipe()

    commands = """
print "[42, None, 'hello']"

def greet(name, count):
    for i in range(count):
        print "Hello, " + name + "!"

greet("Beth Cooper", 5)
fugazi
print "Still going..."
"""
    p = Process(target=myfunc, args=(child_conn, commands))
    p.start()
    print parent_conn.recv()
    p.join()

关于安全性的常见警告在这里适用(即,除非您可以相信这些代码段的发送者不要做任何愚蠢/恶意的操作,否则请不要这样做.)

The usual caveats about security apply here (i.e., don't do this unless you can trust the sender of these code snippets to not do anything stupid/malicious).

还请注意,如果您不需要解释python表达式语句的任意组合,则可以简化很多操作.如果您只需要调用生成某些输出的***函数,则可能更合适:

Also note that you can simplify this a lot if you don't need to interpret an arbitrary mix of python expressions and statements. If you only need to call a top-level function that generates some outputs, something like this may be more appropriate:

def dosomething():
    print "Doing something..."

def myfunc(conn, command):
    output = StringIO()
    result = ""
    with std_redirector(stdout=output, stderr=output):
        try:
            eval(command)
            result = output.getvalue()
        except Exception, err:
            result = repr(err)

    conn.send(result)
    conn.close()

if __name__ == '__main__':
    parent_conn, child_conn = Pipe()
    command = "dosomething()"
    p = Process(target=myfunc, args=(child_conn, command))
    p.start()
    print parent_conn.recv()
    p.join()