我需要处理来自网络摄像头的帧并将一些选定的帧发送到远程websocket服务器。服务器立即回复确认消息(很像回显服务器)。 帧处理速度慢且CPU密集,因此我想使用单独的线程池(生产者)来使用所有可用的核心。所以客户端(消费者)只是闲置,直到池有东西要发送。 我当前的实现,见下文,只有在我在生产者测试循环中添加一个小睡眠时才能正常工作。如果我删除此延迟,我将停止从服务器(echo服务器和我的真实服务器)接收任何应答。即使第一个答案丢失了,所以我认为这不是一个防洪机制。 我做错了什么?
client.useXpath().click("//*[matches(@*, '/\b[19]{1,2}.([May]{3,}|[05]{1,2}).[2017]{4}\b/g')]");
在我的真实节目中,我使用"窗口,如"保护消费者的机制(autobahn.twisted.websocket服务器):生产者可以发送最多数量的未确认消息(网络摄像头帧),然后停止等待一半的窗口释放。 消费者发送" PROCESSED"消息回复确认一条或多条消息(只是一个计数器,而不是id)。 我在消费者日志中看到的是消息被处理并且答案被发回,但这些消息在网络中的某处消失了。
我对asynchio的经验很少,所以我想确保我不会错过任何收益,注释或其他内容。
这是消费者方面的日志:
import tornado
from tornado.websocket import websocket_connect
from tornado import gen, queues
import time
class TornadoClient(object):
url = None
onMessageReceived = None
onMessageSent = None
ioloop = tornado.ioloop.IOLoop.current()
q = queues.Queue()
def __init__(self, url, onMessageReceived, onMessageSent):
self.url = url
self.onMessageReceived = onMessageReceived
self.onMessageSent = onMessageSent
def enqueueMessage(self, msgData, binary=False):
print("TornadoClient.enqueueMessage")
self.ioloop.add_callback(self.addToQueue, (msgData, binary))
print("TornadoClient.enqueueMessage done")
@gen.coroutine
def addToQueue(self, msgTuple):
yield self.q.put(msgTuple)
@gen.coroutine
def main_loop(self):
connection = None
try:
while True:
while connection is None:
try:
print("Connecting...")
connection = yield websocket_connect(self.url)
print("Connected " + str(connection))
except Exception, e:
print("Exception on connection " + str(e))
connection = None
print("Retry in a few seconds...")
yield gen.Task(self.ioloop.add_timeout, time.time() + 3)
try:
print("Waiting for data to send...")
msgData, binaryVal = yield self.q.get()
print("Writing...")
sendFuture = connection.write_message(msgData, binary=binaryVal)
print("Write scheduled...")
finally:
self.q.task_done()
yield sendFuture
self.onMessageSent("Sent ok")
print("Write done. Reading...")
msg = yield connection.read_message()
print("Got msg.")
self.onMessageReceived(msg)
if msg is None:
print("Connection lost")
connection = None
print("main loop completed")
except Exception, e:
print("ExceptionExceptionException")
print(e)
connection = None
print("Exit main_loop function")
def start(self):
self.ioloop.run_sync(self.main_loop)
print("Main loop completed")
######### TEST METHODS #########
def sendMessages(client):
time.sleep(2) #TEST only: wait for client startup
while True:
client.enqueueMessage("msgData", binary=False)
time.sleep(1) # <--- comment this line to break it
def testPrintMessage(msg):
print("Received: " + str(msg))
def testPrintSentMessage(msg):
print("Sent: " + msg)
if __name__=='__main__':
from threading import Thread
client = TornadoClient("ws://echo.websocket.org", testPrintMessage, testPrintSentMessage)
thread = Thread(target = sendMessages, args = (client, ))
thread.start()
client.start()
答案 0 :(得分:0)
这是一个很好的代码。我相信你需要在sendMessages
线程中休眠的原因是因为它会一直尽可能快地调用enqueueMessage
,每秒数百万次。由于enqueueMessage
不等待处理排队的消息,因此它会尽可能快地调用IOLoop.add_callback
,而不会给循环足够的机会来执行回调。< / p>
循环可能会在主线程上运行某些进度,因为您实际上并未阻止它。但是sendMessages
线程添加回调比循环可以处理它们快得多。当循环从队列中弹出一条消息并开始处理它时,已经添加了数百万个新的回调,循环必须在它进入下一个消息处理阶段之前执行。
因此,对于您的测试代码,我认为在线程上调用enqueueMessage
之间休眠是正确的。