关于Python Twisted框架,有人可以向我解释如何将非常大的数据字符串异步写入消费者,比如protocol.transport对象吗?
我认为我缺少的是write(data_chunk)
函数,它返回Deferred
。这就是我想做的事情:
data_block = get_lots_and_lots_data()
CHUNK_SIZE = 1024 # write 1-K at a time.
def write_chunk(data, i):
d = transport.deferredWrite(data[i:i+CHUNK_SIZE])
d.addCallback(write_chunk, data, i+1)
write_chunk(data, 0)
但是,在Twisted API / Documentation中闲逛了一天之后,我似乎找不到像deferredWrite
等价的东西。我错过了什么?
答案 0 :(得分:8)
正如让 - 保罗所说,你应该使用IProducer and IConsumer,但你也应该注意到deferredWrite
的缺失是有点故意的遗漏。
首先,为可能写入的每个数据字节创建Deferred
是一个性能问题:我们在web2
项目中尝试过它,发现它是最重要的性能问题整个系统,我们正试图避免这个错误,因为我们将web2
代码反向移植到twisted.web
。
更重要的是,当Deferred
“完成”时返回write
将会产生误导性的印象:电线的另一端已收到您发送的数据。没有合理的方法来辨别这一点。代理,智能路由器,应用程序错误和各种网络设计都可能会让你误以为你的数据实际上已经到达了连接的另一端,即使它从未被处理过。如果您需要知道另一端已经处理了您的数据,请确保您的应用程序协议具有仅在收到并处理数据后才会发送的确认消息。
在这种代码中使用生产者和使用者的主要原因是首先避免分配内存。如果你的代码确实首先将所有要写入其对等体的数据读入内存中的一个巨大字符串(data_block = get_lots_and_lots_data()
非常直接暗示这一点)那么你不会因为transport.write(data_block)
而失去太多。传输将唤醒并尽可能多地发送大量数据。此外,您可以简单地执行transport.write(hugeString)
然后transport.loseConnection()
,并且在所有数据都已发送或连接被中断之前,传输实际上不会断开连接。 (同样:如果你不等待确认,你就不会知道数据是否到达那里。但是如果你只是想将一些字节转储到套接字中而忘记它,那么这就行了。)
如果get_lots_and_lots_data()
实际上正在阅读文件,则可以使用包含的FileSender类。如果它有点像文件但不完全正确,the implementation of FileSender可能是一个有用的例子。
答案 1 :(得分:1)
通常在Twisted中处理大量数据的方式是使用Producer/Consumer APIs。这不会为您提供返回write
的{{1}}方法,但它确实会为您提供有关何时编写更多数据的通知。