Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sync code to async, without rewriting the function

Basically I have synchronous code something similar to this:

def f(.):
   ...
def call(.):
   ..Some sync code..
   try:
      resp = f(..)
      ...some more transformations of resp...
          return ..
   except:
      ..Some error handling..

async def af(.):
    ...

Basically I want to dynamically alter the code of call so that it can call and await af function instead of f. Is there a way around this? I have found syncit on github, but it doesn't seem to be a solution to me as you have to rewerite the code to async first and then downgrade it to sync. Any help will be appreciated.

like image 555
JukesOnYou Avatar asked Jul 01 '18 19:07

JukesOnYou


People also ask

How do you convert synchronous to asynchronous?

Convert Synchronous to Asynchronous The typical way to make a synchronous function asynchronous is to execute the function in a separate thread. Notice how SyncToAsync finishes and returns control to the program immediately, while SyncMethod executes asynchronously in the background.

Does async await make code synchronous?

Async/await statements are syntactic sugar created on top of JavaScript Promises. They allow us to write Promise-based code as if it were synchronous, but without blocking the main thread.

Which is faster async or sync?

Sync is blocking — it will only send the server one request at a time and will wait for that request to be answered by the server. Async increases throughput because multiple operations can run at the same time. Sync is slower and more methodical.

Can I call async function from Sync Python?

Async functions can directly call sync functions, and if that sync function blocks, then so does the async function calling it.


1 Answers

Here are two options mixing synchronous and asynchronous code.

Given

import asyncio

import trio

from unsync import unsync

Code

Option 1 - trio

Given sync code (call), call an async function via trio (async_div):

# Sync code
def call(x, y):
    """Return an awaited result."""
    try:
        resp = async_div(x, y)
    except ZeroDivisionError:
        return "Caught an exception."
    return resp
    

# Wrapper
def async_div(*args):
    """Return results from an async function."""
    return trio.run(_async_div, *args)


# Async code
async def _async_div(x, y):
    """Return an async result."""
    await trio.sleep(3)
    return x / y

Option 2 - unsync

Decorate the async code with @unsync and call the result():

# Sync code
def call(x, y):
    """Return an awaited result."""
    try:
        resp = async_div(x, y).result()
    except ZeroDivisionError:
        return "Caught an exception."
    return resp


# Async code
@unsync
async def async_div(x, y):
    """Return an async result."""
    await asyncio.sleep(3)
    return x / y

Demo

After the prescribed delay (3 secs), the results are the same:

call(0, 1)
# 0.0

call(1, 0)
# 'Caught an exception.'

See Also

Some additional resources:

  • docs on trio
  • Talk Python interview with trio creator N. Smith for more details and his philosophy on asynchronous programming.
  • Python Bytes episode 73, item 6 on quick unsync details
  • M. Kennedy's webinar demo on using unsync to speed up requests
like image 77
pylang Avatar answered Oct 18 '22 13:10

pylang