> For the complete documentation index, see [llms.txt](https://openai.gitbook.io/code-cheatsheets/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://openai.gitbook.io/code-cheatsheets/all/python/async.md).

# Async Options

* `concurrent.futures` (thread pooling)
* `threading`
* `multiprocessing`
* `asyncio`

```python
if io_bound:
    if io_very_slow:
        print("Use Asyncio") #Many connections
    else:
       print("Use Threads") #Limited connections
else: 
    print("Multi Processing") #CPU Bound
```

## Asyncio

### Why asyncio?

Well, Global Interpreter Lock aka GIL was introduced to make CPython’s memory handling easier and to allow better integrations with C (for example the extensions). The GIL is a locking mechanism that the Python interpreter runs **only one thread at a time.** Multiple process work, but are expensive.

The revolution is the *event loop*. An event loop basically waits for something to happen and then acts on the event. The event loop tracks different I/O events and switches to tasks which are ready and pauses the ones which are waiting on I/O. Thus we don’t waste time on tasks which are not ready to run right now. Single threaded, but gives apperance of parallelism through waiting on I/O.

### Background

**As of 9/8/18, async doesn't work very well in jupyter notebooks(probs displaying errors and underlying event loop already running)**

Async python stand library, new in py version 3.4

Uses **coroutines** which allow a ft to return without losing its state i.e python yielding iterators. Difference with threads is these are collaborative and only one coroutine run at a time, while threads are parallel

ask is a wrapper for a coroutine and a subclass of Future.

## Async/Await

Python has native support for async functions defining a coroutine. Calling these functions doesn't run the code, but returns a JS promise-like coroutine object

```python
import asyncio

async def ping_server(ip):  
    pass

@asyncio.coroutine
def load_file(path):  
    pass
```

To actually call these fts, use `await` inside another ft

```python
async def ping_local():  
    return await ping_server('192.168.1.1')
```

## Event Loop

```python
asyncio.get_event_loop().run_until_complete(my_ft()) #run ft is blocking
```

To add something to event loop

```python
asyncio.ensure_future(my_ft())
```

```python
asyncio.run(main()) #open, run, and close event loop
loop.run_forever() #run forever
```

## Important Fts

```python
await asyncio.sleep(5) #to sleep

page.waitForSelector('h3 a', { timeout: 5000 }) # default timeout 30 seconds
```

### Async For/With

Async for

```python
async def main():
    g = [i async for i in mygen()]
    f = [j async for j in mygen() if not (j // 3 % 5)]
    return g, f

g, f = asyncio.run(main())
```

Allows other coroutines to take turns inbetween loops

## Tasks

These let you return values from a sync ft and ??

```python
import asyncio


async def my_task(seconds):
    print('This task is taking {} seconds to complete'.format(seconds))
    await asyncio.sleep(seconds)
    return 'task finished'


if __name__ == '__main__':
    my_event_loop = asyncio.get_event_loop()
    try:
        print('task creation started')
        task_obj = my_event_loop.create_task(my_task(seconds=2))
        my_event_loop.run_until_complete(task_obj)
    finally:
        my_event_loop.close()

    print("The task's result was: {}".format(task_obj.result()))
```

## Example

We use `aiohttp` for async requests, if we just used urllib or something then this whole async thing wouldn't be helpful.

Writing is still sync, but could use async file io lib

```python
import aiohttp
import asyncio
import async_timeout
import os


async def download_coroutine(session, url):
    with async_timeout.timeout(10):
        async with session.get(url) as response:
            filename = os.path.basename(url)
            with open(filename, 'wb') as f_handle:
                while True:
                    chunk = await response.content.read(1024)
                    if not chunk:
                        break
                    f_handle.write(chunk)
            return await response.release()


async def main(loop):
    urls = ["http://www.irs.gov/pub/irs-pdf/f1040.pdf",
        "http://www.irs.gov/pub/irs-pdf/f1040a.pdf",
        "http://www.irs.gov/pub/irs-pdf/f1040ez.pdf",
        "http://www.irs.gov/pub/irs-pdf/f1040es.pdf",
        "http://www.irs.gov/pub/irs-pdf/f1040sb.pdf"]

    async with aiohttp.ClientSession(loop=loop) as session:
        tasks = [download_coroutine(session, url) for url in urls]
        await asyncio.gather(*tasks)


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main(loop))
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://openai.gitbook.io/code-cheatsheets/all/python/async.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
