我想使用Twisted从队列传输数据。我目前使用推送生成器来轮询队列中的项目并写入传输。
class Producer:
implements(interfaces.IPushProducer)
def __init__(self, protocol, queue):
self.queue = queue
self.protocol = protocol
def resumeProducing(self):
self.paused = False
while not self.paused:
try:
data = self.queue.get_nowait()
logger.debug("Transmitting: '%s'", repr(data))
data = cPickle.dumps(data)
self.protocol.transport.write(data + "\r\n")
except Empty:
pass
def pauseProducing(self):
logger.debug("Transmitter paused.")
self.paused = True
def stopProducing(self):
pass
问题是,数据发送非常不规律,如果队列中只有一个项目,则永远不会发送数据。似乎Twisted等待直到要传输的数据增长到特定值,直到它发送它为止。 我是以正确的方式实施制作人的方式吗?我可以强制Twisted传输数据现在?
我也尝试过使用pull生成器,但Twisted根本不会调用它的resumeProducing()
方法。使用拉动生成器时,是否必须从外部调用resumeProducer()
方法?
答案 0 :(得分:2)
很难说如果没有看到完整的示例(也就是说,没有看到向消费者注册代码的代码以及将项目放入该队列的代码),为什么你的生产者不能正常工作。
但是,您可能遇到的一个问题是,如果在调用resumeProducing
时您的队列为空,那么您根本不会向使用者写入任何字节。当项目被放入队列时,他们将永远坐在那里,因为消费者不会再次调用您的resumeProducing
方法。
这概括为任何其他情况,其中队列中没有足够的数据导致消费者在您的生产者上调用pauseProducing
。作为推送制作人,在消费者致电pauseProducing
(或stopProducing
)之前,您自己继续自行生成数据是您的工作。
对于这种特殊情况,这可能意味着每当你要在该队列中放置一些内容时 - 停止:检查生产者是否未暂停,如果不是,请将其写入消费者代替即可。暂停生产者时,只将物品放入队列。
答案 1 :(得分:-1)
以下是两种可能的解决方案:
1)定期轮询您的本地应用程序,看看您是否还有其他数据要发送。
NB。这依赖于来自扭曲的deferLater方法的定期异步回调。如果您需要一个响应式应用程序,可以按需发送数据,或者需要长时间运行的阻塞操作(例如,使用自己的事件循环的ui),那么它可能不合适。
代码:
from twisted.internet.protocol import Factory
from twisted.internet.endpoints import TCP4ServerEndpoint
from twisted.internet.interfaces import IPushProducer
from twisted.internet.task import deferLater, cooperate
from twisted.internet.protocol import Protocol
from twisted.internet import reactor
from zope.interface import implementer
import time
# Deferred action
def periodically_poll_for_push_actions_async(reactor, protocol):
while True:
protocol.send(b"Hello World\n")
yield deferLater(reactor, 2, lambda: None)
# Push protocol
@implementer(IPushProducer)
class PushProtocol(Protocol):
def connectionMade(self):
self.transport.registerProducer(self, True)
gen = periodically_poll_for_push_actions_async(self.transport.reactor, self)
self.task = cooperate(gen)
def dataReceived(self, data):
self.transport.write(data)
def send(self, data):
self.transport.write(data)
def pauseProducing(self):
print 'Workload paused'
self.task.pause()
def resumeProducing(self):
print 'Workload resumed'
self.task.resume()
def stopProducing(self):
print 'Workload stopped'
self.task.stop()
def connectionLost(self, reason):
print 'Connection lost'
try:
self.task.stop()
except:
pass
# Push factory
class PushFactory(Factory):
def buildProtocol(self, addr):
return PushProtocol()
# Run the reactor that serves everything
endpoint = TCP4ServerEndpoint(reactor, 8089)
endpoint.listen(PushFactory())
reactor.run()
2)手动跟踪Protocol实例并使用来自不同线程的reactor.callFromThread()。允许您在另一个线程(例如,ui事件循环)中使用长阻塞操作。
代码:
from twisted.internet.protocol import Factory
from twisted.internet.endpoints import TCP4ServerEndpoint
from twisted.internet.interfaces import IPushProducer
from twisted.internet.task import deferLater, cooperate
from twisted.internet.protocol import Protocol
from twisted.internet import reactor, threads
import time
import random
import threading
# Connection
protocol = None
# Some other thread that does whatever it likes.
class SomeThread(threading.Thread):
def run(self):
while True:
print("Thread loop")
time.sleep(random.randint(0, 4))
if protocol is not None:
reactor.callFromThread(self.dispatch)
def dispatch(self):
global protocol
protocol.send("Hello World\n")
# Push protocol
class PushProtocol(Protocol):
def connectionMade(self):
global protocol
protocol = self
def dataReceived(self, data):
self.transport.write(data)
def send(self, data):
self.transport.write(data)
def connectionLost(self, reason):
print 'Connection lost'
# Push factory
class PushFactory(Factory):
def buildProtocol(self, addr):
return PushProtocol()
# Start thread
other = SomeThread()
other.start()
# Run the reactor that serves everything
endpoint = TCP4ServerEndpoint(reactor, 8089)
endpoint.listen(PushFactory())
reactor.run()
就个人而言,我发现IPushProducer和IPullProducer需要定期回调这一事实,使它们不那么有用。其他人不同意...... 耸肩。随便挑选。