#python #async-await #python-asyncio
#python #async-await #python-asyncio
Вопрос:
У меня есть идея использовать цикл обработки событий на сервере на основе websocket (на основе websockets
библиотеки), но я изо всех сил пытаюсь это сделать, поскольку я действительно не понимаю, как использовать asyncio
и писать свои собственные сопрограммы.
# let us define a dictionary of callbacks awaiting to be triggered
CALLBACKS = dict()
# let us have an infinite loop, which reads new messages from a websocket connection
async def websocket_connection(ws, path):
async for msg in ws:
# we received a message
msg = json.loads(msg)
msg_id = msg['id']
msg_data = msg['data']
# we check, if there is a callback waiting to be triggered with such id
if msg_id in CALLBACKS:
# if such id exists, we get the callback function
callback = CALLBACKS[msg_id]
# we delete the callback from the dictionary
del CALLBACKS[msg_id]
# we call it passing the data from the message in there
callback(msg_data)
else:
# we don't have such id, throw some error
raise Exception("bad id " msg_id)
# this is the function which submits a message
async def submit(ws, data):
# it generates a random request id
from uuid import uuid4
request_id = str(uuid4())
# registers a callback, which will simply return the received data
CALLBACKS[request_id] = lambda data: # <- this is the part I don't know what it should really do to be able to return the value from the await
# after it encodes the message as json
msg = json.dumps({'id': request_id, 'data': data})
# and sends via the websocket
await ws.send(msg)
# and let us have the actual function, which will be the actual script
async def websocket_script(ws):
# this is what I would like to be able to do in the end.
# pass in commands to the websocket and await their completion
sum = int(await submit(ws, {"eval": "2 2"}))
division = float(await submit(ws, {"eval": "3/2"}))
websocket_connection
и websocket_script
для его работы нужно было бы работать бок о бок. Я полагаю gather
, или какая-то другая async
функция будет работать. Я бы очень хотел избавиться от обратных вызовов, поскольку это первоначальная цель использования asyncio
в первую очередь.
Как это можно сделать? Похоже, это работа для asyncio
.
Ответ №1:
Я думаю, что вы ищете asyncio.Будущее, если я вас правильно понимаю.
FUTURES = dict()
async def websocket_connection(ws, path):
# ...
fut = FUTURES[msg_id]
fut.set_result(msg_data) # will "unblock" await fut below
del FUTURES[msg_id]
# ...
async def submit(ws, data):
from uuid import uuid4
request_id = str(uuid4())
fut = asyncio.Future()
FUTURES[request_id] = fut
msg = json.dumps({'id': request_id, 'data': data})
await ws.send(msg)
# ...
return (await fut)
async def websocket_script(ws):
sum = int(await submit(ws, {"eval": "2 2"}))
division = float(await submit(ws, {"eval": "3/2"}))
Комментарии:
1. спасибо, нигде больше не видел решения.