我正在尝试实现这个简单的工作流程:
现在,这听起来很简单。但我完全坚持第二部分。我无法让我的线程在准备就绪时将数据推送到客户端。
我试过了:
ZeroRPC流。我设法流式传输数据,但是......我无法将计算数据传递给此流。
的WebSockets。使用Python设置ws似乎需要高级技能......我设法设置了websocket服务器。它在一个线程中运行,并侦听客户端消息。 但我无法将此服务器传递给我的计算线程,以便它可以通过它发送数据。
以下是一些示例代码:
def init_socket_server(self, host='localhost', port='8765'):
# the socket handler
async def hello(websocket, path):
# that websocket object is what I need, but it lives in
# its own thread, I can't figure how to get it in other threads
name = await websocket.recv()
print("< {}".format(name))
greeting = "Hello {}!".format(name)
await websocket.send(greeting)
print("> {}".format(greeting))
# this object does not seem to be my actual server, just some init function?
start_server = websockets.serve(hello, host, port)
self.socket_server = start_server
# creating the thread
loop = asyncio.get_event_loop()
def start():
loop.run_until_complete(start_server)
loop.run_forever()
self.socket_thread = Thread(target=start, name="socket_server")
self.socket_thread.start()
这很棘手,因为我需要服务器在自己的线程中运行,否则会阻塞我的整个代码(我必须为其他目的运行多个线程,所以它们都必须在后台)。
然而,似乎我的self.socket_server = start_server
错了。 start_server
似乎不是服务器本身,而是一些Serve
对象。
必须发送数据并在另一个线程中运行的队列:
# this lives in another thread
def _consume_view_queue(self):
while True:
if not VIEW_REQUEST_QUEUE.empty():
request = VIEW_REQUEST_QUEUE.get()
if request:
data = self.doSmth(request)
# does not work as I expect
# I do not seem to have the right object
self.socket_server.send('DATA READY ' + view_id)
VIEW_REQUEST_QUEUE.task_done()
失败了,因为我的self.socket_server
听起来不对。这是错误:
AttributeError: 'Serve' object has no attribute 'send'
很抱歉,如果它是一个欺骗或noob问题,但我发现没有有用的资源(并且websockets / asyncio docs在这里并没有真正帮助......)。
编辑:我设法使用全局共享websocketServer
对象。虽然不起作用,但我仍然有AttributeError: 'WebSocketServer' object has no attribute 'send'
。我不明白为什么我的ws服务器没有send
方法。
编辑2:所以你有更多的背景,我正在构建一个电子应用程序。电子应用程序是一个chrome客户端,类似于任何Web应用程序和本地节点服务器。这个应用程序还启动python进程进行计算。
到目前为止,Python和JS代码以“同步”方式与RPC调用进行通信:客户端请求数据,服务器接收请求并立即对其进行处理,然后回答请求。当计算量很大时,它是不好的,你不能按优先级排序它们。所以我实现了一个等待队列:计算请求堆叠在这个队列中。这样更健壮,可以很好地扩展,并允许按优先级对计算进行排序。
但是现在计算存在于一个独立的线程中,该线程运行一个消耗队列的无限循环。据我所知,这是消耗队列的常用模式。但我从未设法将这些数据传递回客户端。我希望这个计算线程能够将事件发送到我的JS客户端,我尝试了ZeroRPC流,我尝试了websockets但没有成功。我可以将数据存储在另一个队列中,以便我可以从我的websocket服务器所在的线程访问它们。但是,似乎你无法监听队列更改来触发事件,所以你需要一个无限循环来消耗它,因此另一个线程......我无法弄明白:)
答案 0 :(得分:2)
通常,在事件&#34;浏览器中执行此类&#34;唤醒JS的阻力最小的路径是让JS向您的服务器发布XMLHttpRequest,并且具有 您的服务器保持挂起的请求(通常是GET,但可以根据您的REST设计使用任何HTTP操作)。当你有数据时,那么你 用数据完成该请求。客户端可以处理/显示它,然后发布新请求。
查看:http://en.wikipedia.org/wiki/Long_polling
你通常会想要一个&#34;代#34;请求中的计数器,通常是一个URL参数,如&#34; http://myserver.com/nextdata.json?gen=1234&#34;所以你的 服务器知道何时立即发送数据(例如,来自第0代客户端的第一个请求)或保持直到有新数据。
正如此处暗示的那样,通常您将数据编码为JSON,因为它是在REST / WWW世界中移动数据的一种非常简单的方法,并且Python具有 优秀的JSON解析模块。
答案 1 :(得分:0)
我最终找到了一个有效的工作流程。我的答案并不遥远,我的错误是尝试将套接字服务器从其线程中移出,并且我无法编写正确的协程。
相反,我使用了第二个队列来存储计算,我也写了正确的协程:
async def send_data_to_client(websocket, path):
while True:
data = OUTPUT_QUEUE.get()
await websocket.send(data)
OUTPUT_QUEUE.task_done()
start_server = websockets.serve(send_data_to_client, host, port)
loop = asyncio.get_event_loop()
def start_socket_server():
loop.run_until_complete(start_server)
loop.run_forever()
self.socket_thread = Thread(target=start_socket_server, daemon=True, name="socket_server")
self.socket_thread.start()
它遵循9000在他的评论中总结的工作流程。使用asyncio,我们甚至可以将此生成器循环组合到消息使用循环see the websockets
doc。