Skip to main content

Smoothly migrate your synchronous codebase to the asynchronous style.

Project description

Aiofutures

Python version Tests PyPI - Downloads

General information

aiofutures provides tools to integrate an asynchronous code into your synchronous application in a usual and easy way using standard library's concurrent.futures.Executor interface.

It may be useful when you want to:

  • smoothly migrate your synchronous codebase to asynchronous style
  • decrease a number of threads in your application

Replace this:

from concurrent.futures import ThreadPoolExecutor

with ThreadPoolExecutor() as ex:
    future = ex.submit(sync_task)
    result = future.result()

With this:

from aiofutures import AsyncExecutor

with AsyncExecutor() as ex:
    future = ex.submit(async_task)
    result = future.result()

The former spawns a lot of threads and experiences all cons of GIL, the latter spawns the only one async thread (check out notes)

Installation

You can install aiofutures using pip:

pip install aiofutures

Usage

Implicit initialization (global executor)

Set an environment variable AIOFUTURES_INIT to any value and use shortcuts from the library:

os.environ.setdefault('AIOFUTURES_INIT', '1')

from aiofutures import run_async

async def io_bound_task(seconds):
    await asyncio.sleep(seconds)
    return seconds

future = run_async(io_bound_task, 5)
print(future.result())

AIOFUTURES_INIT implicitly initializes a global AsyncExecutor and gives you an option to use shortcuts run_async and sync_to_async.

Explicit initialization

Use an instance of the AsyncExecutor directly:

from aiofutures import AsyncExecutor

executor = AsyncExecutor()
future = executor.submit(io_bound_task, 5)
print(future.result())

In cases when you need to do IO synchronously within async tasks, you can use sync_to_async:

from aiofutures import AsyncExecutor, sync_to_async

executor = AsyncExecutor()

async def io_bound_task():
    # or with the shortcut
    # url = await sync_to_async(fetch_url_from_db_sync)
    url = await executor.sync_to_async(fetch_url_from_db_sync)
    data = await fetch_data(url)
    return data

future = executor.submit(io_bound_task)
print(future.result())

NOTE: You can use sync_to_async within tasks running in the executor only.

UVLoop

To use with the high performance uvloop install it before initialization:

# install before the import for the global executor
import uvloop
uvloop.install()
from aiofutures import run_async
...

# or before an explicit initialization
import uvloop
from aiofutures import AsyncExecutor
uvloop.install()
executor = AsyncExecutor()

Notes

  • Take into account that asyncio still (CPython3.11) resolves DNS in threads, not asynchronously
  • Any blocking function will block the whole AsyncExecutor

Contribution

All suggestions are welcome!

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aiofutures-0.1.2.tar.gz (5.1 kB view hashes)

Uploaded Source

Built Distribution

aiofutures-0.1.2-py3-none-any.whl (5.8 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page