Python 3.5 Asyncio and Multiple websocket servers

2019-08-27 17:26发布

问题:

I am using Python websockets 4.0.1 on Ubuntu. I want to have 2 websocket servers running. I was able to get this to "kind of work" by creating 2 threads and independent event loops for each one. By "kind of work", I mean both websockets work and are responsive for about 30 seconds and then one of them stops. I have to restart the process to get them both to work again. If I only run one or the other of these 2 threads, the single websocket works forever.

What am I doing wrong and how can I have 2 websockets work forever with asyncio? Thanks.

# 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()

回答1:

You don't need threads to run multiple asyncio tasks - allowing multiple agents to share the same event loop is the strong suit of asyncio. You should be able to replace both thread-based classes with code like this:

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

While it is not exactly wrong to mix threads and asyncio, doing so correctly requires care not to mix up the separate asyncio instances. The safe way to use threads for asyncio is with loop.run_in_executor(), which runs synchronous code in a separate thread without blocking the event loop, while returning an object awaitable from the loop.