python-trio / unasync

The async transformation code.
Other
89 stars 13 forks source link

JIT #72

Open davidbrochart opened 3 years ago

davidbrochart commented 3 years ago

Would it make sense to allow for just-in-time generation (and execution) of the synchronous code?

sethmlarson commented 3 years ago

You'd run into problems where the code is used within a read-only file system. There would also be problems with type hints/suggestions when developing with the code.

pquentin commented 3 years ago

Right, JIT seems like too much magic. Why would you need that?

Reading https://github.com/jupyter/jupyter_client/issues/624, what seems more useful is to be able to tell unasync to ignore code that is deliberately async. Another option is to call async code from the sync parts, possibly using the world's simplest coroutine runner:

def _run_secretly_sync_async_fn(async_fn, *args, **kwargs):
    coro = async_fn(*args, **kwargs)
    try:
        coro.send(None)
    except StopIteration as exc:
        return exc.value
    else:
        raise RuntimeError("this async function is not secretly synchronous")

(Even though that won't help for _async_poll_for_reply in nbclient.)

For what it's worth, unasync is currently used successfully in httpcore and the Python Elasticsearch client. As as unasync maintainer, I'm very interested to see use cases where it does not work, so I subscribed to that issue and will be interested to see what comes out of it.

davidbrochart commented 3 years ago

Right, JIT seems like too much magic. Why would you need that?

Essentially to not worry about the generated sync files: whether to commit them or not, having the extra step of generating them each time the async code changes... Generating sync code on the fly would feel much more like there is one source of truth.

Reading jupyter/jupyter_client#624, what seems more useful is to be able to tell unasync to ignore code that is deliberately async.

But then in the sync world you'll have to run this code until complete in an event loop, which is what we wanted to avoid with unasync.

Another option is to call async code from the sync parts, possibly using the world's simplest coroutine runner:

def _run_secretly_sync_async_fn(async_fn, *args, **kwargs):
    coro = async_fn(*args, **kwargs)
    try:
        coro.send(None)
    except StopIteration as exc:
        return exc.value
    else:
        raise RuntimeError("this async function is not secretly synchronous")

(Even though that won't help for _async_poll_for_reply in nbclient.)

I don't see how you can run async code with this function, but yes running a coroutine until complete in an event loop is an option, although it also comes with complications when an event loop is already running.

For what it's worth, unasync is currently used successfully in httpcore and the Python Elasticsearch client. As as unasync maintainer, I'm very interested to see use cases where it does not work, so I subscribed to that issue and will be interested to see what comes out of it.

Good to know, for jupyter-client I came to the conclusion that unasync is not an option, as we (can) have async code that is impossible to translate to sync.