![](/img/trans.png)
[英]Socket vs. multiprocessing.connection.Listener in python
[英]Non-blocking multiprocessing.connection.Listener?
我使用 multiprocessing.connection.Listener 进行进程之间的通信,它对我来说很有魅力。 现在我真的很喜欢我的主循环在来自客户端的命令之间做其他事情。 不幸的是 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()
我发现的一种解决方案(尽管它可能不是最“优雅”的解决方案是使用conn.poll
。( 文档)如果 Listener 有新数据,则 Poll 返回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
用于此目的的参考资料。
我自己没有使用过 Listener 对象——对于这个任务,我通常使用multiprocessing.Queue
; doco 在以下链接:
https://docs.python.org/2/library/queue.html#Queue.Queue
该对象可用于通过良好的 API 在 Python 进程之间发送和接收任何可腌制的对象; 我想你最感兴趣的是:
.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()
队列很好,因为对于完全相同的 Queue 对象,您实际上可以拥有尽可能多的消费者和生产者(对于分发任务很方便)。
我应该指出,仅在 Process 上调用.terminate()
是不好的形式 - 您应该使用闪亮的新消息系统来传递关闭消息或类似性质的消息。
多处理模块带有一个很好的特性,叫做 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)
这应该将其保持在无限循环中,直到另一个进程完成运行并发送结果。 这也比队列快 2-3 倍。 尽管队列也是一个不错的选择,但我个人不使用它。
您可以在线程中运行阻塞函数:
conn = await loop.run_in_executor(None, listener.accept)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.