python管道的同步/异步行为
在我的应用程序中,我使用来自多处理模块的管道在python进程之间进行通信。 最近,我观察到一种奇怪的行为,这取决于我通过它们发送的数据的大小。 根据python文档,这些管道是基于连接的,应该以异步方式运行,但有时它们在发送时会卡住。如果我在每个连接中启用全双工,那么一切都可以正常工作,即使我没有将连接用于发送和侦听。 有人能解释这种行为吗python管道的同步/异步行为,python,linux,multiprocessing,pipe,Python,Linux,Multiprocessing,Pipe,在我的应用程序中,我使用来自多处理模块的管道在python进程之间进行通信。 最近,我观察到一种奇怪的行为,这取决于我通过它们发送的数据的大小。 根据python文档,这些管道是基于连接的,应该以异步方式运行,但有时它们在发送时会卡住。如果我在每个连接中启用全双工,那么一切都可以正常工作,即使我没有将连接用于发送和侦听。 有人能解释这种行为吗 100个浮点数,全双工禁用 代码利用异步性工作 100个浮点数,全双工启用 该示例工作正常 10000个浮点,全双工禁用 执行将永远被阻止,即使对于较小的
代码利用异步性工作
该示例工作正常
执行将永远被阻止,即使对于较小的数据执行情况良好
又好了
首先,值得注意的是类的实现 不同之处在于半双工“管道”使用a,而全双工“管道”实际上使用a,因为匿名管道本质上是单向的 我不知道你在这里所说的“异步”是什么意思。如果您的意思是“非阻塞I/O”,那么值得注意的是,这两种实现在默认情况下都使用阻塞I/O
其次,值得注意的是,您试图发送的数据的大小
>>> from numpy.random import randn
>>> from cPickle import dumps
>>> len(dumps(randn(100)))
2479
>>> len(dumps(randn(10000)))
237154
第三,从
管道(7)
手册页
管道容量
管道的容量有限。如果管道已满,则写入(2)将被阻塞
或失败,取决于是否设置了O_非块标志(见下文)。不同的
实现对管道容量有不同的限制。申请应
不依赖于特定的容量:应用程序的设计应确保
读取过程在数据可用时立即消耗数据,因此写入过程
不会保持阻塞状态
在2.6.11之前的Linux版本中,管道的容量与系统相同
页面大小(例如,i386上的4096字节)。自Linux 2.6.11以来,管道容量为
65536字节
因此,实际上,您创建了一个死锁,其中所有子进程都阻塞了
pipe_out.send()
调用,并且它们都无法从其他进程接收任何数据,因为您在一次命中中发送了所有237154字节的数据,这已经填充了65536字节的缓冲区
您可能只想使用Unix域套接字版本,但目前它工作的唯一原因是它的缓冲区大小比管道大,如果将数据点的数量增加到100000,您会发现该解决方案也将失败
“quick n'dirty hack”解决方案是将数据分成更小的数据块进行发送,但依赖特定大小的缓冲区并不是一种好的做法
更好的解决方案是在pipe\u out.send()
调用上使用非阻塞I/O,尽管我对多处理
模块不太熟悉,无法确定使用该模块实现它的最佳方法
伪代码应该是
while 1:
if we have sent all data and received all data:
break
send as much data as we can without blocking
receive as much data as we can without blocking
if we didn't send or receive anything in this iteration:
sleep for a bit so we don't waste CPU time
continue
…或者您可以使用Python模块来避免睡眠时间过长,但是,再次强调,将其与多处理.Pipe集成可能很棘手
这门课可能会为你做所有这些,但我以前从未使用过,所以你必须做一些实验。谢谢你详尽的回答。现在我明白了。
>>> from numpy.random import randn
>>> from cPickle import dumps
>>> len(dumps(randn(100)))
2479
>>> len(dumps(randn(10000)))
237154
while 1:
if we have sent all data and received all data:
break
send as much data as we can without blocking
receive as much data as we can without blocking
if we didn't send or receive anything in this iteration:
sleep for a bit so we don't waste CPU time
continue