【问题标题】:How can I integrate Python mido and asyncio?如何集成 Python mido 和 asyncio?
【发布时间】:2019-05-23 14:28:17
【问题描述】:

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

【问题讨论】:

    标签: python python-asyncio mido


    【解决方案1】:

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

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

    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 在其后台线程中调用回调时,您的 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)
    

    【讨论】:

    • 这正是我正在寻找的,但它为我打印的只是源源不断的 不管我是否发送任何 MIDI 数据。我知道它未经测试,但我很难找出问题所在..
    • 我将yield queue.get() 更改为yield await queue.get()。那成功了。谢谢!
    • @Genoil 你是对的! queue 是一个异步队列,所以它的 get() 方法是一个协程,必须等待,呵呵!顺便说一句,您使用的是哪个版本的 Python?
    • 我们在 3.6.10
    • @Genoil 谢谢,这解释了 generator object Queue.get 的输出,一开始让我失望 - asyncio.Queue 被修改为使用 async def蟒蛇 3.7。您可能需要考虑切换到较新的版本; Python 3.7 大约在两年前发布。
    猜你喜欢
    • 2020-12-18
    • 1970-01-01
    • 2018-10-22
    • 1970-01-01
    • 2019-11-18
    • 2010-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多