繁体   English   中英

Python多处理,从子进程读取输入

[英]Python multiprocessing, read input from child process

我有一个多处理系统,有一个主进程和两个子进程。

其中一个子进程(例如,C1)通过队列向另一个子进程(C2)发送消息。 C2 分析来自 C1 的消息,当某些条件发生时,它需要用户的一些输入。

所以,情况是这样的:

主文件

from child_process_01 import Child_Process_01
from child_process_02 import Child_Process_02

set_start_method("spawn")

c1_c2_q = Queue(maxsize=1)

c1 = mp.Process(target=Child_Process_01, args=(c1_c2_q,))
c1.daemon = True
c1.start()

c2 = mp.Process(target=Child_Process_02, args=(c1_c2_q,))
c2.daemon = True
c2.start()

Child_Process_01

message = produced somehow
c1_c2_q.put((message))

Child_Process_02

## infinite loop, keep checking messages and ask for user input under certain conditions

while True:
    try:
        message = c1_c2_q.get_nowait()
    except:
        message = None

    ## when message arrives
    if message:
        if message = something:
            usr_input = input('In this situation, I need user input')  

代码无法正常工作,因为多处理模块关闭了它创建的所有进程的标准输入,正如我在此处的许多答案中发现的那样。 一个很好的建议似乎是在主流程中重新定义标准并将其发送给孩子,如解释herehere ,所以我尝试了:

主文件

newstdin = os.fdopen(os.dup(sys.stdin.fileno()))

c2 = mp.Process(target=Child_Process_02, args=(c1_c2_q, newstdin))
c2.daemon = True
c2.start()

Child_Process_02

def Child_Process_02(c1_c2_q, newstdin):
    sys.stdin = newstdin
    while True:
        try:
            message = c1_c2_q.get_nowait()
        except:
            message = None

        ## when message arrives
        if message:
            if message = something:
                usr_input = input('In this situation, I need user input')  

但这也不起作用,因为我无法通过队列传递在主进程中创建的 newstdin 对象,我收到错误消息:

TypeError: cannot pickle '_io.TextIOWrapper' object

此外,对类似问题的一些评论通常不鼓励从子进程中读取输入的做法,但我无法想象如何以不同的方式做到这一点。 有什么建议?

首先,您应该修改Child_Process_02以免消耗太多 CPU 周期,通过使用阻塞调用c1_c2_q.get()c1_c2_q.get_nowait()进行非生产性调用,该调用在收到消息之前不会返回(并且您可以获得摆脱围绕此调用的try/except脚手架)。

其次,这是可选的,因为您从Child_Process_01传递到Child_Process_02消息有一个生产者和一个消费者,您可以通过调用multiprocessing.Pipe(duplex=False)替换multiprocessing.Queue来提高效率,这将返回两个单向multiprocessing.connection.Connection实例,其中第二个适合发送任意对象,例如字符串,第一个适合接收对象(顺便说一下, multiprocessing.Queue是在Pipe之上实现的)。 但是一个全双工Pipe ,其中每个连接都可以用于发送和接收,这绝对是以下程序所需要的,其中主进程启动的线程通过调用multiprocessing.connection.Connection.recv()来“侦听”执行input调用的请求multiprocessing.connection.Connection.recv()循环。 此调用返回的消息是用于调用input的提示字符串。 然后input函数返回的值将在连接上sent回:

from multiprocessing import Process, Pipe
from threading import Thread

def inputter(input_conn):
    """ get requests to do input calls """
    while True:
        input_msg = input_conn.recv()
        value = input(input_msg)
        input_conn.send(value) # send inputted value:


def worker(msg_conn, input_conn):
    while True:
        message = msg_conn.recv()
        if message is None:
            break
        if message == 'do input':
            # send inputter our prompt message:
            input_conn.send('Enter x: ')
            # get back the result of the input:
            x = (int)(input_conn.recv())
            print('The value entered was', x)
        else:
            print('Got message:', message)


if __name__ == '__main__':
    import time

    # create the connections for sending messages from one process to another:
    recv_conn, send_conn = Pipe(duplex=False)

    # create the connections for doing the input requests:
    input_conn1, input_conn2 = Pipe(duplex=True) # each connection is bi-drectional

    # start the inputter thread with one of the inputter duplex connections:
    t = Thread(target=inputter, args=(input_conn1,), daemon=True)
    t.start()

    # start a child process with the message connection in lieu of a Queue
    # and the other inputter connection:
    p = Process(target=worker, args=(recv_conn, input_conn2))
    p.start()

    # send messages to worker process:
    send_conn.send('a')
    send_conn.send('do input')
    send_conn.send('b')
    # signal the child process to terminate:
    send_conn.send(None)
    p.join()

印刷:

Got message: a
Enter x: 8
The value entered was 8
Got message: b

笔记

应当指出的是, multiprocessing.Queue开始为底层饲养线程multiprocessing.Pipe防止“推杆”从之前MAXSIZE呼叫过早阻塞put已经作出,其中最大范围是用于实例队列值。 但这也是multiprocessing.Queue性能不如multiprocessing.Pipe 但这也意味着在连接上重复调用send而另一端没有相应的recv调用最终会阻塞。 但鉴于您已在队列中指定maxsize=1 ,这几乎不是问题,因为在与队列相同的情况下您会阻塞。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM