mido
предоставляет основанный на обратном вызове API , который будет вызывать обратный вызов из другого потока.Ваша реализация обратного вызова может связаться с asyncio, позвонив loop.call_soon_threadsafe
.Обратите внимание, что вы не сможете просто установить значение Future
, потому что обратный вызов будет вызываться несколько раз, а будущее может быть задано только один раз - оно предназначено для однократных вычислений..
Распространенный шаблон для многократных обратных вызовов заключается в том, чтобы помещать события в асинхронную очередь и извлекать из нее информацию в асинхронном коде.Это можно сделать еще более удобным, выставив очередь в качестве асинхронного итератора.Эта функция автоматизирует процесс:
async def make_stream():
loop = asyncio.get_event_loop()
queue = asyncio.Queue()
def callback(message):
loop.call_soon_threadsafe(queue.put_nowait, message)
async def stream():
while True:
yield queue.get()
return callback, stream()
make_stream
возвращает два объекта:
- a обратный вызов , который можно передать на
mido.open_input()
- поток, который вы можете перебрать с
async for
для получения новых сообщений
Всякий раз, когда обратный вызов вызывается mido в фоновом потоке, ваш asyncio async for
цикл итерации по потоку проснется с новым элементом.По сути, make_iter
преобразует многопоточный обратный вызов в асинхронный итератор.Например (не проверено):
async def print_messages():
# create a callback/stream pair and pass callback to mido
cb, stream = make_stream()
mido.open_input(callback=cb)
# print messages as they come just by reading from stream
async for message in stream:
print(message)