Как я могу интегрировать Python Mido и Asyncio?
У меня есть устройство, которое делает файл ввода-вывода через MIDI. У меня есть скрипт с использованием Mido, который загружает файлы, но это беспорядок глобальных переменных. Я хочу привести в порядок правильное использование asyncio, но я не уверен, как интегрировать обратный вызов mido. Я думаю, что документация говорит, что я должен использовать объект Future, но я не уверен, как функция обратного вызова mido может получить этот объект.
1 ответ
mido
предоставляет основанный на обратном вызове API, который будет вызывать обратный вызов из другого потока. Ваша реализация обратного вызова может связаться с Asyncio, позвонив loop.call_soon_threadsafe
, Обратите внимание, что вы не сможете просто установить значение Future
потому что обратный вызов будет вызываться несколько раз, а будущее может быть установлено только один раз - он предназначен для однократных вычислений.
Обычным шаблоном для многократных обратных вызовов является отправка событий в очередь asyncio и извлечение из нее содержимого в асинхронном коде. Это можно сделать еще более удобным, выставив очередь в качестве асинхронного итератора. Эта функция автоматизирует процесс:
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
возвращает два объекта:
- обратный вызов, который вы можете передать
mido.open_input()
- поток, с которым вы можете перебирать
async for
получать новые сообщения
Всякий раз, когда обратный вызов вызывается Mido в фоновом потоке, ваша асинхронность 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)