Как я могу интегрировать Python Mido и Asyncio? - PullRequest
1 голос
/ 23 мая 2019

У меня есть устройство, которое выполняет файловый ввод / вывод через MIDI.У меня есть скрипт с использованием Mido, который загружает файлы, но это беспорядок глобальных переменных.Я хочу привести в порядок правильное использование asyncio, но я не уверен, как интегрировать обратный вызов mido.Я думаю, что документация говорит, что я должен использовать объект Future, но я не уверен, как функция обратного вызова mido может получить этот объект.

1 Ответ

2 голосов
/ 23 мая 2019

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)
...