我正在寻找有关Python中Queues实现的更多见解,而不是我在文档中找到的。
根据我的理解,如果我错了,请原谅我的无知:
queue.Queue()
:通过内存中的基本数组实现,因此不能在多个进程之间共享,但可以在线程之间共享。到目前为止,非常好。
multiprocessing.Queue()
:是通过管道(man 2 pipes
)实现的,这些管道具有大小限制(相当小:在Linux上,man 7 pipe
表示65536未经处理):
自Linux 2.6.35起,默认管道容量为65536字节,但可以使用
fcntl(2)
F_GETPIPE_SZ
和F_SETPIPE_SZ
操作查询和设置容量
但是,在Python中,每当我尝试将大于65536字节的数据写入管道时,它都可以毫无例外地工作 - 我可以通过这种方式充斥我的记忆:
import multiprocessing
from time import sleep
def big():
result = ""
for i in range(1,70000):
result += ","+str(i)
return result # 408888 bytes string
def writequeue(q):
while True:
q.put(big())
sleep(0.1)
if __name__ == '__main__':
q = multiprocessing.Queue()
p = multiprocessing.Process(target=writequeue, args=(q,))
p.start()
while True:
sleep(1) # No pipe consumption, we just want to flood the pipe
所以这是我的问题:
Python会调整管道限制吗?如果是的话,多少钱?欢迎使用Python源代码。
Python管道通信是否可以与其他非Python进程互操作?如果是,欢迎工作示例(最好是JS)和资源链接。
答案 0 :(得分:10)
mutiprocessing.Queue
创建一个管道,如果管道已满,则会阻塞。当然,写入超过管道容量将导致write
调用阻塞,直到读取端清除了足够的数据。好的,所以如果管道在达到其容量时阻塞,为什么管道满了时q.put()
还阻塞?即使第一次调用示例中的q.put()
也应该填满管道,一切都应该阻塞,不是吗?
不,它不会阻止,因为multiprocessing.Queue
实现将.put()
方法与写入管道解耦。 .put()
方法将传递的数据排入队列在内部缓冲区中,有一个单独的线程,负责读取此缓冲区并写入管道。管道已满时,此线程将阻塞,但不会阻止.put()
将更多数据排入内部缓冲区。
.put()的实施将数据保存到self._buffer
,并注意如果没有一个线程已经在运行,它将如何启动线程:
def put(self, obj, block=True, timeout=None):
assert not self._closed
if not self._sem.acquire(block, timeout):
raise Full
with self._notempty:
if self._thread is None:
self._start_thread()
self._buffer.append(obj)
self._notempty.notify()
._feed()
方法是从self._buffer
读取并将数据提供给管道的方法。而._start_thread()
是设置运行._feed()
。
如果你想限制可以写入队列的数据量,我不会通过指定字节数看到一种方法,但你可以限制存储在内部的项目数量通过将数字传递给multiprocessing.Queue
:
q = multiprocessing.Queue(2)
当我使用上面的参数并使用您的代码时,q.put()
会将两个项目排入队列,并在第三次尝试时阻止。
这取决于。 multiprocessing
模块提供的工具不易与其他语言互操作。我希望可能使multiprocessing
与其他语言互操作,但实现这一目标将是一个重要的事业。编写该模块时期望所涉及的进程正在运行Python代码。
如果你看一下更通用的方法,那么答案是肯定的。您可以使用套接字作为两个不同进程之间的通信管道。例如,从命名套接字读取的JavaScript进程:
var net = require("net");
var fs = require("fs");
sockPath = "/tmp/test.sock"
try {
fs.unlinkSync(sockPath);
}
catch (ex) {
// Don't care if the path does not exist, but rethrow if we get
// another error.
if (ex.code !== "ENOENT") {
throw ex;
}
}
var server = net.createServer(function(stream) {
stream.on("data", function(c) {
console.log("received:", c.toString());
});
stream.on("end", function() {
server.close();
});
});
server.listen(sockPath);
写入它的Python进程:
import socket
import time
sockfile = "/tmp/test.sock"
conn = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
conn.connect(sockfile)
count = 0
while True:
count += 1
conn.sendall(bytes(str(count), "utf-8"))
time.sleep(1)
如果你想尝试上面的内容,你需要先启动JavaScript端,以便Python端有东西可以写入。这是一个概念验证。一个完整的解决方案需要更多的润色。
为了将复杂的结构从Python传递到其他语言,您必须找到一种以双面可读取的格式序列化数据的方法。不幸的是,Pickles特定于Python。我通常在需要在语言之间进行序列化时选择JSON,或者如果JSON不能这样做,则使用ad-hoc格式。