我使用multiprocessing.connection.Listener进行进程之间的通信,它对我来说是一个魅力。现在我真的很喜欢我的mainloop在客户端的命令之间做一些其他事情。不幸的是,listener.accept()会阻止执行,直到建立客户端进程的连接为止。
是否有一种简单的方法来管理multiprocessing.connection的非阻塞检查?超时?或者我应该使用专用线程吗?
# Simplified code:
from multiprocessing.connection import Listener
def mainloop():
listener = Listener(address=(localhost, 6000), authkey=b'secret')
while True:
conn = listener.accept() # <--- This blocks!
msg = conn.recv()
print ('got message: %r' % msg)
conn.close()
答案 0 :(得分:1)
我发现的一个解决方案(尽管它可能不是最“优雅”的解决方案)正在使用conn.poll
。(documentation)如果侦听器有新数据,则轮询将返回True
,并且(最重要的是)如果没有传递任何参数,它就是非阻塞的。我不是100%地确定这是最好的方法,但是我成功运行了一次,只运行一次listener.accept()
,然后使用以下语法重复获取输入(如果有的话)
from multiprocessing.connection import Listener
def mainloop():
running = True
listener = Listener(address=(localhost, 6000), authkey=b'secret')
conn = listener.accept()
msg = ""
while running:
while conn.poll():
msg = conn.recv()
print (f"got message: {msg}")
if msg == "EXIT":
running = False
# Other code can go here
print(f"I can run too! Last msg received was {msg}")
conn.close()
如果您一次只想获取最多一条消息,则条件语句中的“ while”可以替换为“ if”。请谨慎使用,因为它似乎有点“ hacky”,我在其他地方也没有找到为此目的而使用conn.poll
的引用。
答案 1 :(得分:0)
我自己没有使用过Listener对象 - 我通常使用multiprocessing.Queue
这个任务; doco在以下链接:
https://docs.python.org/2/library/queue.html#Queue.Queue
该对象可用于在Python进程之间使用漂亮的API发送和接收任何可pickle对象;我想你最感兴趣的是:
.put('some message')
.get_nowait() # will raise Queue.Empty if nothing is available- handle that to move on with your execution
唯一的限制是你需要在某个时刻控制两个Process对象,以便能够将队列分配给它们 - 如下所示:
import time
from Queue import Empty
from multiprocessing import Queue, Process
def receiver(q):
while 1:
try:
message = q.get_nowait()
print 'receiver got', message
except Empty:
print 'nothing to receive, sleeping'
time.sleep(1)
def sender(q):
while 1:
message = 'some message'
q.put('some message')
print 'sender sent', message
time.sleep(1)
some_queue = Queue()
process_a = Process(
target=receiver,
args=(some_queue,)
)
process_b = Process(
target=sender,
args=(some_queue,)
)
process_a.start()
process_b.start()
print 'ctrl + c to exit'
try:
while 1:
time.sleep(1)
except KeyboardInterrupt:
pass
process_a.terminate()
process_b.terminate()
process_a.join()
process_b.join()
队列很好,因为你可以拥有尽可能多的消费者和许多生产者,以获得完全相同的队列对象(方便分发任务)。
我应该指出,只是在进程上调用.terminate()
是不好的形式 - 你应该使用闪亮的新消息系统来传递关闭消息或那种性质的东西。
答案 2 :(得分:0)
多处理模块具有一个不错的功能,称为Pipe()。这是在两个进程之间共享资源的好方法(以前从未尝试过两个以上)。随着python 3.80的到来,多处理模块中出现了共享内存功能,但是我还没有真正测试过,因此我无法为其提供担保 您将使用
之类的管道功能from multiprocessing import Pipe
.....
def sending(conn):
message = 'some message'
#perform some code
conn.send(message)
conn.close()
receiver, sender = Pipe()
p = Process(target=sending, args=(sender,))
p.start()
print receiver.recv() # prints "some message"
p.join()
有了这个,您应该能够有独立运行的单独进程,并且当您需要一个进程的输入时。如果由于另一个进程的数据无法获取而导致某种错误,则可以将其置于某种睡眠或停止状态,或者使用while循环不断检查另一个进程完成该任务并通过其发送时的挂起状态
while not parent_conn.recv():
time.sleep(5)
这应该使它处于无限循环状态,直到其他进程运行完毕并发送结果为止。这也比Queue快2-3倍。尽管就个人而言,队列也是一个不错的选择,但我不使用它。
答案 3 :(得分:0)
您可以在线程中运行阻止功能:
conn = await loop.run_in_executor(None, listener.accept)