【问题标题】:Create a lock/unlock mechanism in async mode for Python在异步模式下为 Python 创建锁定/解锁机制
【发布时间】:2021-03-14 03:28:38
【问题描述】:

我在 JS 中有这个 new_lock 函数,它对避免回调地狱很有用:

function new_lock(){
    var unlock,lock = new Promise((res,rej)=>{ unlock=res; });
    return [lock,unlock];
}

var [lock,unlock] = new_lock();
call_some_func_with_callback(data,function(){
    print(1);
    print(2);
    unlock();
});
await lock;

print(3)

这是我在里面使用“await”关键字的异步 Python 主函数:

import asyncio as aio

def new_lock():
    ?How to put code here?
    return lock,unlock

async main():
    lock,unlock = new_lock()

    def cb(ackdata):
       print(1)
       print(2)
       unlock()

    # Python web server emits to client side (browser)
    socketio.emit("eventname",data,callback=cb)
    await lock

    print(3)

if __name__=="__main__":
    loop = aio.get_event_loop()
    t = loop.create_task(main())
    loop.run_until_complete(t)

如何在 JS 中创建与“new_lock”函数等效的 Python?甚至是 Python 中必需的 new_lock 函数?

【问题讨论】:

  • "甚至是 Python 中必需的 new_lock 函数?" 我不太确定 JS 中是否需要该函数。见How do I convert an existing callback API to promises? 编辑:虽然,我不得不承认,这是一个非常聪明的实现。我确实喜欢它在技术层面上,但是有前途的回调是优越的,因为你可以立即使用整个 Promise API,包括await。还有一些用于承诺回调的库。

标签: javascript python promise async-await python-asyncio


【解决方案1】:

您没有展示如何设置和运行socketio 库。如果 socketio 在 asyncio 内部运行(即它从事件循环线程调用回调),那么您的“锁”将转换为 asyncio Future,其使用方式与 JavaScript Promise 大致相同:

def new_lock():
    loop = asyncio.get_event_loop()
    fut = loop.create_future()
    def unlock():
        fut.set_result(None)
    return fut, unlock

如果 socketio 不在 asyncio 内部运行,即如果它在单独的线程中运行,它将调用传递给 emit 的回调,那么上面的内容是不够的。在这种情况下,您需要使用线程感知调用来唤醒事件循环并告诉它设置未来的结果:

def new_lock():
    loop = asyncio.get_event_loop()
    fut = loop.create_future()
    def unlock():
        loop.call_soon_threadsafe(fut.set_result, None)
    return fut, unlock

【讨论】:

    【解决方案2】:

    为什么不只使用socket.io's AsyncClientAsyncServer 类而只使用await sio.emit()

    否则,您正在寻找 an Event async 原语:

    import asyncio as aio
    
    async main():
        ev = aio.Event()
    
        def cb(ackdata):
           print(1)
           print(2)
           ev.set()
    
        await socketio.emit("eventname",data,callback=cb)
        await ev.wait()
        print(3)
    

    【讨论】:

    • 我的客户端不是python,它是浏览器中的javascript,js库来自socket.io
    • 我明白,但是您的问题是关于使用 Socket.io 库的异步 Python 代码,并且您正在尝试执行 Socket.io 已经对异步客户端执行的操作。
    • tks,aio.Event() 很简单,lock=ev.wait(),unlock=ev.set
    • asyncio.Event 会在 OP 的代码中工作吗? socketio 客户端示例通常以sio.wait() 结尾,看起来它有自己的事件循环。
    • 我在 socketio.emit 之前添加了 'await' 并且它起作用了
    【解决方案3】:

    我在 Python 中使用 asyncio 模块的 new_lock 函数

    import asyncio as aio
    
    def new_lock():
        event = aio.Event()
        return event.wait(),event.set
    
    async def main():
       lock,unlock = new_lock()
       ...
       await lock
       ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-20
      • 1970-01-01
      • 1970-01-01
      • 2020-02-17
      相关资源
      最近更新 更多