YouTip LogoYouTip

Python Asyncio

Python3.x Python asyncio Module

\\n\\n

asyncio is a module in the Python standard library for writing asynchronous I/O operations code.

\\n\\n

asyncio provides an efficient way to handle concurrent tasks, especially suitable for I/O-intensive operations such as network requests, file read/write, etc.

\\n\\n

By using asyncio, you can handle multiple tasks simultaneously in a single thread without using multithreading or multiprocessing.

\\n\\n

Why do we need asyncio?

\\n\\n

In traditional synchronous programming, when a task needs to wait for an I/O operation (such as a network request) to complete, the program blocks until the operation is finished. This leads to low program efficiency, especially when dealing with a large number of I/O operations.

\\n\\n

asyncio improves program concurrency and efficiency by introducing an asynchronous programming model that allows the program to continue executing other tasks while waiting for I/O operations.

\\n\\n
\\n

Imagine you are running a restaurant:

\\n
    \\n
  • Synchronous mode (ordinary function): You have only one chef. Guest A orders a steak, and the chef starts cooking it (which takes 5 minutes). During these 5 minutes of cooking, the chef is completely occupied and cannot do anything else. Even if Guest B just wants a glass of water, they must wait idly.
  • \\n
  • Asynchronous mode (asyncio): You have multiple chefs (actually still one, but very smart). After the chef starts cooking Guest A's steak, realizing it needs to wait, they immediately mark that steak as pending, then turn to pour water for Guest B. After pouring the water, they check if the steak is almost ready; if not, they can go handle Guest C's order. This way, during the waiting time for I/O (such as cooking steak, network requests, reading/writing files), the chef (CPU) is constantly working efficiently.
  • \\n
\\n

asyncio is the standard library Python uses to implement this smart working pattern. It allows you to write single-threaded concurrent code, especially suitable for I/O-intensive scenarios such as web crawlers, web servers, and microservices.

\\n
\\n\\n

Its core components are the event loop, coroutines, and tasks.

\\n\\n
\\n\\n

1. Coroutine

\\n\\n

Coroutine is one of the core concepts of asyncio. It is a special function that can pause during execution and resume later. Coroutines are defined with the async def keyword and paused with the await keyword, waiting for asynchronous operations to complete.

\\n\\n

Example

\\n\\n
import asyncio\\n\\nasync def say_hello():\\n    print("Hello")\\n    await asyncio.sleep(1)\\n    print("World")\\n
\\n\\n

2. Event Loop

\\n\\n

The event loop is the core component of asyncio, responsible for scheduling and executing coroutines. It continuously checks if there are tasks to execute and calls the corresponding callback functions after tasks are completed.

\\n\\n

Example

\\n\\n
async def main():\\n    await say_hello()\\n\\nasyncio.run(main())\\n
\\n\\n

3. Task

\\n\\n

A task is a wrapper for a coroutine, representing a coroutine that is currently executing or will be executed. You can create tasks through the asyncio.create_task() function and add them to the event loop.

\\n\\n

Example

\\n\\n
async def main():\\n    task = asyncio.create_task(say_hello())\\n    await task\\n
\\n\\n

4. Future

\\n\\n

Future is an object representing the result of an asynchronous operation. It is typically used in low-level APIs to represent an operation that has not yet completed. You can wait for a Future to complete using the await keyword.

\\n\\n

Example

\\n\\n
async def main():\\n    future = asyncio.Future()\\n    await future\\n
\\n\\n

Basic Usage and Code Examples

\\n\\n

Let's understand the above concepts through a classic example of concurrently accessing multiple URLs.

\\n\\n

Suppose we need to fetch content from three different URLs. Using synchronous methods would execute them sequentially, with total time being the sum of the three request durations. Using asyncio, we can send these three requests simultaneously, with total time close to the slowest request.

\\n\\n

Synchronous Version (for comparison)

\\n\\n

Example

\\n\\n
import time\\nimport requests\\n\\ndef fetch_url(url):\\n    """Simulate a time-consuming network request (synchronous version)"""\\n    print(f"Start fetching: {url}")\\n    time.sleep(2)  # Simulate 2 seconds network delay\\n    print(f"Finish fetching: {url}")\\n    return f"From {url} Data"\\n\\ndef main_sync():\\n    urls = ['https://example.com/1', 'https://example.com/2', 'https://example.com/3']\\n    results = []\\n    \\n    start = time.time()\\n    \\n    for url in urls:\\n        result = fetch_url(url)  # Must wait for the previous one to complete before starting the next\\n        results.append(result)\\n    \\n    end = time.time()\\n    \\n    print(f"Synchronous version total time taken: {end - start:.2f} Seconds")\\n    print(f"Result: {results}")\\n\\nif __name__ == "__main__":\\n    main_sync()\\n
\\n\\n

Expected Output:

\\n\\n
Start fetching: https://example.com/1\\nFinish fetching: https://example.com/1\\nStart fetching: https://example.com/2\\nFinish fetching: https://example.com/2\\nStart fetching: https://example.com/3\\nFinish fetching: https://example.com/3\\nSynchronous version total time taken: 6.00 Seconds\\nResult: ['From https://example.com/1 Data', 'From https://example.com/2 Data', 'From https://example.com/2 Data']\\n
\\n

Total time spent is approximately 6 seconds.

\\n\\n

Asynchronous Version (using asyncio)

\\n\\n

We need to use the aiohttp library instead of requests for asynchronous HTTP requests. First install it: pip install aiohttp.

\\n\\n

Example

\\n\\n
import asyncio\\nimport aiohttp\\nimport time\\n\\nasync def fetch_url_async(session, url):\\n    """Simulate a time-consuming network request (asynchronous version)"""\\n    print(f"Start asynchronous fetching: {url}")\\n    # Note: Here we use aiohttp's asynchronous get method, and await it\\n    \\n    async with session.get(url) as response:\\n        # Simulate processing response also takes time\\n        await asyncio.sleep(2)  # Use asyncio.sleep to simulate I/O waiting, it does not block the thread\\n        text = await response.text()\\n    \\n    print(f"Finish asynchronous fetching: {url}")\\n    return f"From {url} Data (Length: {len(text)})"\\n\\nasync def main_async():\\n    urls = ['https://httpbin.org/get', 'https://httpbin.org/delay/1', 'https://httpbin.org/headers']\\n    \\n    async with aiohttp.ClientSession() as session:  # Create asynchronous HTTP session\\n        # Create a task for each URL\\n        tasks = []\\n        for url in urls:\\n            # create_task adds the coroutine to the event loop and immediately starts scheduling\\n            task = asyncio.create_task(fetch_url_async(session, url))\\n            tasks.append(task)\\n        \\n        print("All tasks have been created, starting concurrent execution...")\\n        \\n        # Use asyncio.gather to run all tasks concurrently and wait for them all to complete\\n        # gather returns a list of results, in the same order as the tasks passed in\\n        results = await asyncio.gather(*tasks)\\n    \\n    return results\\n\\nif __name__ == "__main__":\\n    start = time.time()\\n    # asyncio.run() is a convenient way to start the event loop and run the top-level coroutine\\n    final_results = asyncio.run(main_async())\\n    end = time.time()\\n    \\n    print(f"nAsynchronous version total time taken: {end - start:.2f} Seconds")\\n    for res in final_results:\\n        print(res)\\n
\\n\\n

Expected Output:

\\n\\n
All tasks have been created, starting concurrent execution...\\nStart asynchronous fetching: https://httpbin.org/get\\nStart asynchronous fetching: https://httpbin.org/delay/1\\nStart asynchronous fetching: https://httpbin.org/headers\\n(About 2 SecondsPost, all requests complete almost simultaneously)\\nFinish asynchronous fetching: https://httpbin.org/headers\\nFinish asynchronous fetching: https://httpbin.org/get\\nFinish asynchronous fetching: https://httpbin.org/delay/1\\n\\nAsynchronous version total time taken: 2.10 Seconds  # Note! The total elapsed time is far less than 6 seconds\\nFrom https://httpbin.org/get Data (Length: 274)\\nFrom https://httpbin.org/delay/1 Data (Length: 392)\\nFrom https://httpbin.org/headers Data (Length: 177)\\n
\\n\\n

Code Analysis:

\\n\\n
    \\n
  • async def: Defines the coroutine functions fetch_url_async and main_async.
  • \\n
  • await: In fetch_url_async, we await session.get() and await response.text(), which tells the event loop: "This network request takes time, go ahead and execute other ready tasks."
  • \\n
  • asyncio.create_task(): Wraps the fetch_url_async coroutine into a Task, allowing it to be scheduled by the event loop to achieve concurrency.
  • \\n
  • asyncio.gather(*tasks): A very practical function that runs all passed coroutines/tasks concurrently, waits for them all to complete, and finally collects all results.
  • \\n
  • asyncio.run(main_async()): The recommended way in Python 3.7+, it is responsible for creating the event loop, running the coroutine, and closing the loop.
  • \\n
\\n\\n

Key Functions and Parameters Explanation

\\n\\n

Below are the most commonly used high-level functions in asyncio in table form:

\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n
FunctionMain PurposeCommon Parameters
asyncio.run(coro, *, debug=False)Run a top-level coroutine, managing the lifecycle of the event loop. This is the main entry point of the program.coro: The coroutine object to run. debug: Set to True to enable debug mode for the event loop.
asyncio.create_task(coro, *, name=None)Wrap a coroutine into a Task object and schedule it in the event loop. This is the main way to achieve concurrency.coro: The coroutine object to wrap. name: (Python 3.8+) Assign a name to the task for easier debugging.
asyncio.gather(*aws, return_exceptions=False)Run multiple asynchronous tasks concurrently (aws can accept coroutines, tasks, etc.), wait for all to complete, and return a list of results.*aws: Variable arguments, pass multiple asynchronous objects. return_exceptions: Defaults to False; if any task raises an exception, it will immediately propagate to the caller of gather. When set to True, exceptions will be returned as part of the results.
asyncio.sleep(delay, result=None)Asynchronously sleep for the specified number of seconds. This is the key difference from time.sleep (blocking).delay: Number of seconds to sleep. result: Value to return after sleep completes.
asyncio.wait(aws, *, timeout=None, return_when=ALL_COMPLETED)Run tasks concurrently and wait until the specified condition is met. Returns two sets (done, pending), which are completed and pending tasks respectively.aws: Collection of asynchronous objects. timeout: Timeout in seconds. return_when: Determines when to return, options: FIRST_COMPLETED (first completed), FIRST_EXCEPTION (first exception), ALL_COMPLETED (all completed, default).
asyncio.to_thread(func, /, *args, **kwargs)(Python 3.9+) Run an ordinary, potentially blocking synchronous function in a separate thread and return an awaitable coroutine. Used for handling CPU-intensive or blocking I/O.func: The synchronous function to run in the thread. *args, **kwargs: Arguments passed to the function.
\\n\\n

Visual Understanding: Asynchronous Task Scheduling Flow

\\n\\n

Image 1

\\n\\n

Diagram Explanation: This flowchart shows how the event loop works like a dispatcher. It maintains a task queue. When a task reaches await (e.g., waiting for a network response), it is suspended, and the event loop immediately finds the next runnable (ready) task from the queue to execute. When the I/O operation of the suspended task completes, the event loop receives notification, changes that task's status back to ready, and continues executing it at some point in the future. Through this method, during I/O waiting periods, the CPU is fully utilized to execute other tasks, achieving concurrency within a single thread.

\\n\\n
\\n\\n

asyncio Basic Usage

\\n\\n

1. Running Coroutines

\\n\\n

To run a coroutine, you can use the asyncio.run() function. It creates an event loop and runs the specified coroutine.

\\n\\n

Example

\\n\\n
import asyncio\\n\\nasync def main():\\n    print("Start")\\n    await asyncio.sleep(1)\\n    print("End")\\n\\nasyncio.run(main())\\n
\\n\\n

2. Concurrently Executing Multiple Tasks

\\n\\n

You can use the asyncio.gather() function to concurrently execute multiple coroutines and wait for them all to complete.

\\n\\n

Example

\\n\\n
import asyncio\\n\\nasync def task1():\\n    print("Task 1 started")\\n    await asyncio.sleep(1)\\n    print("Task 1 finished")\\n\\nasync def task2():\\n    print("Task 2 started")\\n    await asyncio.sleep(2)\\n    print("Task 2 finished")\\n\\nasync def main():\\n    await asyncio.gather(task1(), task2())\\n\\nasyncio.run(main())\\n
\\n\\n

3. Timeout Control

\\n\\n

You can use the asyncio.wait_for() function to set a timeout for a coroutine. If the coroutine does not complete within the specified time, an asyncio.TimeoutError exception will be raised.

\\n\\n

Example

\\n\\n
import asyncio\\n\\nasync def long_task():\\n    await asyncio.sleep(10)\\n    print("Task finished")\\n\\nasync def main():\\n    try:\\n        await asyncio.wait_for(long_task(), timeout=5)\\n    except asyncio.TimeoutError:\\n        print("Task timed out")\\n\\nasyncio.run(main())\\n
\\n\\n
\\n\\n

asyncio Application Scenarios

\\n\\n

asyncio is particularly suitable for the following scenarios:

\\n\\n
    \\n
  1. Network Requests: Such as HTTP requests, WebSocket communication, etc.
  2. \\n
  3. File I/O: Such as asynchronous file reading/writing.
  4. \\n
  5. Database Operations: Such as asynchronous database access.
  6. \\n
  7. Real-time Data Processing: Such as real-time message queue processing.
  8. \\n
\\n\\n
\\n\\n

Common Classes, Methods, and Functions

\\n\\n

1. Core Functions

\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n
Method/FunctionDescriptionExample
asyncio.run(coro)Run asynchronous main function (Python 3.7+)asyncio.run(main())
asyncio.create_task(coro)Create task and add to event looptask = asyncio.create_task(fetch_data())
asyncio.gather(*coros)Run multiple coroutines concurrentlyawait asyncio.gather(task1, task2)
asyncio.sleep(delay)Asynchronous wait (non-blocking)await asyncio.sleep(1)
asyncio.wait(coros)Control task completion methoddone, pending = await asyncio.wait([task1, task2])
\\n\\n

2. Event Loop

\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n
MethodDescriptionExample
loop.run_until_complete(future)Run until task completesloop.run_until_complete(main())
loop.run_forever()Run event loop foreverloop.run_forever()
← Pycharm IntroPython Csv β†’

YouTip © 2024-2026 | Home | Learn Technology, Build Dreams!

All content is for educational and learning purposes only.