如何集成Python Mido和Asyncio?

2022-03-25 00:00:00 python python-asyncio mido

问题描述

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


解决方案

mido提供了一个callback-based接口,该接口将从不同的线程调用回调。您的回调实现可以通过调用loop.call_soon_threadsafe与异步通信。请注意,您不能只设置Future的值,因为回调将被多次调用,而未来只能设置一次-它用于一次性计算。

多次调用回调的一种常见模式是将事件推送到异步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返回两个对象:

  • 回调,可以传递给mido.open_input()
  • 一个流,可以通过async for迭代得到新消息

每当Mido在其后台线程中调用回调时,在流上迭代的asyncioasync 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)

相关文章