如何整合 Python mido 和 asyncio?

How can I integrate Python mido and asyncio?

我有一个设备可以通过 MIDI 文件 I/O。我有一个使用 Mido 的脚本可以下载文件,但它是一堆全局变量。我想整理一下以正确使用 asyncio,但我不确定如何集成 mido 回调。我认为文档说我应该使用 Future 对象,但我不确定 mido 回调函数如何获取该对象。

mido 提供了一个 callback-based API which will invoke the callback from a different thread. Your implementation of the callback can communicate with asyncio by calling loop.call_soon_threadsafe. Note that you won't be able to just set the value of a Future 因为回调将被调用多次,而未来只能设置一次 - 它用于 one-shot 计算。

多次调用回调的常见模式是将事件推送到异步 queue 并在异步代码中从中弹出内容。通过将队列公开为异步迭代器,这可以变得更加方便。此函数自动执行该过程:

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 await queue.get()
    return callback, stream()

make_stream returns 两个对象:

  • 一个回调,你可以传递给mido.open_input()
  • 一个流,您可以使用 async for 对其进行迭代以获取新消息

每当 mido 在其后台线程中调用回调时,您的 asyncio async for 循环迭代流将唤醒一个新项目。实际上,make_stream 将线程回调转换为异步迭代器。例如(未经测试):

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)