【问题标题】:Python 3.5 Asyncio and Multiple websocket serversPython 3.5 Asyncio 和多​​个 websocket 服务器
【发布时间】:2018-02-16 01:02:51
【问题描述】:

我在 Ubuntu 上使用 Python websockets 4.0.1。我想运行 2 个 websocket 服务器。我能够通过为每个线程创建 2 个线程和独立的事件循环来完成“某种工作”。通过“某种工作”,我的意思是两个 websocket 都工作并且响应大约 30 秒,然后其中一个停止。我必须重新启动该过程才能让它们再次工作。如果我只运行这两个线程中的一个或另一个,则单个 websocket 将永远工作。

我做错了什么,如何让 2 个 websocket 与 asyncio 一起工作?谢谢。

# Start VL WebSocket Task
class vlWebSocketTask (threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self):
        # Main while loops
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        while True:
            try:
                print("Starting VL WebSocket Server...")
                startVLServer = websockets.serve(vlWebsocketServer, '192.168.1.3', 8777)
                asyncio.get_event_loop().run_until_complete(startVLServer)  
                asyncio.get_event_loop().run_forever()
            except Exception as ex:
                print(ex)
            time.sleep(5)

# Start IR WebSocket Task
class irWebSocketTask (threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self):
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        while True:
            try:
                print("Starting IR WebSocket Server...")
                startIRServer = websockets.serve(irWebsocketServer, '192.168.1.3', 8555)
                asyncio.get_event_loop().run_until_complete(startIRServer)  
                asyncio.get_event_loop().run_forever()
            except Exception as ex:
                print(ex)
            time.sleep(5)

# Initialize VL WebSocket Task
#VLWebSocketTask = vlWebSocketTask()
#VLWebSocketTask.start()

# Initialize IR WebSocket Task
IRWebSocketTask = irWebSocketTask()
IRWebSocketTask.start()

【问题讨论】:

    标签: python linux python-3.x websocket python-asyncio


    【解决方案1】:

    您不需要线程来运行多个 asyncio 任务 - 允许多个代理共享同一个事件循环是 asyncio 的强项。您应该能够用如下代码替换这两个基于线程的类:

    loop = asyncio.new_event_loop()
    loop.run_until_complete(websockets.serve(vlWebsocketServer, '192.168.1.3', 8777))
    loop.run_until_complete(websockets.serve(irWebsocketServer, '192.168.1.3', 8555))
    loop.run_forever()
    

    虽然混合线程和 asyncio 并不是完全错误,但正确地这样做需要注意不要混淆单独的 asyncio 实例。将线程用于 asyncio 的安全方法是使用 loop.run_in_executor(),它在单独的线程中运行同步代码而不阻塞事件循环,同时从循环中返回对象 awaitable。

    注意:以上代码是在asyncio.run() 出现之前编写的,并手动旋转事件循环。在 Python 3.7 及更高版本中,可能会编写如下内容:

    async def main():
        server1 = await websockets.serve(vlWebsocketServer, '192.168.1.3', 8777)
        server2 = await websockets.serve(irWebsocketServer, '192.168.1.3', 8555)
        await asyncio.gather(server1.wait_closed(), server2.wait_closed())
    
    asyncio.run(main())
    

    【讨论】:

    • 您是否尝试过运行自己的代码?这将产生类似TypeError: a coroutine was expected, got <websockets.server.Serve object at 0x7baca53e3a90>
    • @AndyPan 我不记得我是否尝试过,但完全有可能我没有尝试过。 serve 也有可能在两年前被定义为 async def 时写这个答案。无论哪种方式,loop.create_task 都可以轻松更改为 asyncio.ensure_future 并获得所需的效果。如果您可以确认这有效,我会相应地更改答案。
    • 首先,显然您应该等待返回的对象。这将为您提供服务器对象。然后使用asyncio.create_task(server.wait_closed())之类的东西。
    • @AndyPan 谢谢,我现在修改了答案。请注意,wait_closed()asyncio.run() 内部运行时是一个方便的等待目标,但将wait_closed() 传递给create_task() 是不必要的,因为一旦server() 完成,无论您是否调用wait_closed(),服务器都会运行。此答案中的前asyncio.run 代码使用run_forever() 来保持循环运行,因此不需要wait_closed()。在编辑中,我包含了实现相同目标的现代方式,正如您所期望的那样使用wait_closed()
    • 为我的傲慢道歉。 websockets.serve 的返回对象没有改变,但我对其工作原理的理解也不准确。由于我在官方文档中找不到解决方案,因此感谢您改进答案。
    猜你喜欢
    • 2019-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-08
    相关资源
    最近更新 更多