1

I have this new_lock function in JS, it's useful to avoid callback hell:

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)

And this is my async Python main function to use 'await' keyword inside:

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)

How to create the Python equivalent of the 'new_lock' function in JS? Or even that new_lock function necessary in Python?

Dee
  • 7,455
  • 6
  • 36
  • 70
  • 1
    "*Or even that new_lock function necessary in Python?*" I'm not really sure the function is needed in JS. See [How do I convert an existing callback API to promises?](https://stackoverflow.com/q/22519784) EDIT: although, I have to admit, it's a very clever implementation. I do like it on a technical level, however promisifying callbacks is superior as you can immediately use the entire promise API including `await`. There are also libraries for promisifying callbacks. – VLAZ Dec 02 '20 at 07:14

3 Answers3

2

Why not just use socket.io's AsyncClient or AsyncServer class and just await sio.emit()?

Failing that, you're looking for an Event async primitive:

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)
Dee
  • 7,455
  • 6
  • 36
  • 70
AKX
  • 152,115
  • 15
  • 115
  • 172
  • my client side is not python, it's javascript in browser and the js lib is from https://socket.io – Dee Dec 02 '20 at 08:07
  • 1
    I understand, but your question is about async Python code that uses the Socket.io library, and you're attempting to do what Socket.io does already with the async client. – AKX Dec 02 '20 at 08:09
  • tks, that aio.Event() is simple enough, lock=ev.wait(), and unlock=ev.set – Dee Dec 02 '20 at 08:31
  • Will `asyncio.Event` work in the OP's code? The socketio client examples usually end with `sio.wait()` which looks like it has its own event loop. – user4815162342 Dec 02 '20 at 08:58
  • i added 'await' before socketio.emit and it worked – Dee Dec 02 '20 at 09:16
1

You don't show how you set up and run the socketio library. If socketio runs inside asyncio (i.e. it invokes the callback from the event loop thread), then your "lock" translates to an asyncio Future used in much the same way as a JavaScript Promise:

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

If socketio doesn't run inside asyncio, i.e. if it runs in a separate thread from which it will invoke the callback passed to emit, then the above is not enough. In that case you need to use thread-aware calls to wake up the event loop and tell it to set the result of the future:

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
user4815162342
  • 141,790
  • 18
  • 296
  • 355
0

My new_lock function for Python using asyncio module

import asyncio as aio

def new_lock():
    event = aio.Event()
    return event.wait(),event.set

async def main():
   lock,unlock = new_lock()
   ...
   await lock
   ...
Dee
  • 7,455
  • 6
  • 36
  • 70