简体   繁体   中英

Websocket freezes program if no clients are connected

I'm creating a real-time event detector. It reads a gaming stream and detects some events there like goals, timer updates and etc. All of the events should be sent via websocket, so I use python websockets and asyncio libraries. Code is the following:

main_stack = []

cap = cv2.VideoCapture("vid_2.mp4")
game = Game(main_stack)


async def handler(websocket):
    while True:
        ret, frame = cap.read()
        await asyncio.sleep(0.05)
        game.run_detectors(frame)
        while main_stack:
            elem = main_stack.pop()
            await websocket.send(elem.get_json())


async def main():
    async with websockets.serve(handler, "", 8765):
        await asyncio.Future()


if __name__ == "__main__":
    asyncio.run(main())

Line game.run_detectors(frame) adds events to main stack if detected. Then if there are some events in the stack, they're sent via websocket. The problem is that when no client is connected, program freezes, missing events from translation which runs in real time. How can I change the code, so that the stack is updated independently of websocket. And websocket constantly checks updates and sends events if they're present in the stack?

You should run the game in a separate thread and add events to a queue , then pop them and send them in a websocket handler. Note that this will only work for a single connection, if you have multiple connections you need to write some kind of logic which holds the state (which events were already sent, etc.) for each of the connections. Without the additional logic only one of the connections will receive an event, not all of them.

Below is a basic example how it should look like.

from threading import Thread
from queue import Queue, Empty
import time

main_stack = Queue()

cap = cv2.VideoCapture("vid_2.mp4")
game = Game(main_stack) # Adapt logic in the Game class to put events in the queue


async def handler(websocket):
    while True:
        try:
            elem = main_stack.get(timeout=1e-3) # Try to fetch an event from queue with a 1 ms timeout in order to prevent high CPU usage
        except Empty:
            continue # In case the queue is empty, repeat fetching
        await websocket.send(elem.get_json())


async def main():
    async with websockets.serve(handler, "", 8765):
        await asyncio.Future()


def game_loop(game, cap):
    while True:
        ret, frame = cap.read()
        game.run_detectors(frame)
        time.sleep(0.05)

if __name__ == "__main__":
    game_thread = Thread(target=game_loop, args=(game, cap), daemon=True)
    game_thread.start()
    asyncio.run(main())

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM