Your Code Freezes? Fix It with Async!
45sImmediately hooks viewers who struggle with slow code by promising a solution to freezing network calls.
▶ Play ClipThis video explains Python's async/await syntax and the asyncio library for running thousands of I/O-bound tasks concurrently on a single thread. It covers coroutines, the event loop, gather, create_task, async context managers, and production patterns like timeouts and semaphores. The tutorial culminates in building a concurrent API fetcher with rate limiting.
Calling an async function returns a coroutine object, not executing the code immediately. To run it, you need await.
Inside a coroutine, await pauses the current task and lets the event loop run other code. When the awaited operation finishes, execution resumes.
It creates a new event loop, runs the main coroutine, and closes the loop. Call it exactly once at the top level of your program.
Pass multiple coroutines to gather; they start immediately and run concurrently. Total time equals the slowest task, not the sum.
Schedules a coroutine to run immediately without waiting. Use await later to collect the result.
Define async methods for setup and cleanup. Use 'async with' to ensure non-blocking resource management.
Wrap a coroutine with a timeout. If it doesn't finish in time, asyncio.TimeoutError is raised.
Create a semaphore with a fixed limit. Use 'async with sem' before each operation to control how many run at once.
An async generator yields values one at a time, awaiting between each. Useful for streaming data.
Combines semaphore, gather, and async context manager to fetch many URLs concurrently while respecting rate limits.
Async/await in Python allows you to run thousands of I/O-bound tasks concurrently on a single thread using cooperative multitasking. Mastering asyncio's core tools—coroutines, gather, create_task, async context managers, timeouts, and semaphores—enables building high-performance concurrent applications.
"Title accurately promises to explain async/await and run many tasks on one thread; the video delivers exactly that."
What does calling an async def function return?
It returns a coroutine object, not executing the code immediately.
00:51
What does await do inside a coroutine?
It pauses the current task and lets the event loop run other code; when the awaited operation finishes, execution resumes.
01:21
What is the entry point for an asyncio program?
asyncio.run(main_coroutine) creates a new event loop, runs the coroutine, and closes the loop.
01:52
How does asyncio.gather differ from sequential await?
gather runs all coroutines concurrently; total time is the slowest task, not the sum.
02:53
What is the purpose of asyncio.create_task?
It schedules a coroutine to run immediately in the background without waiting; you can await it later for the result.
03:50
What special methods must an async context manager implement?
__aenter__ and __aexit__ (both async methods).
04:51
How do you add a timeout to a coroutine?
Wrap it with asyncio.wait_for(coroutine, timeout_seconds); raises TimeoutError if it doesn't finish in time.
05:46
How do you limit concurrency in asyncio?
Use asyncio.Semaphore with a fixed limit and 'async with sem' before each operation.
06:02
What is the syntax for async iteration?
async for item in async_generator: ...
06:19
What does asyncio.sleep do?
It yields control back to the event loop for a non-blocking pause.
06:44
What is asyncio.TaskGroup (Python 3.11+)?
It provides structured concurrency: create tasks inside the group; if any task raises, all others are automatically cancelled.
07:10
What is asyncio.Queue used for?
Async-safe producer-consumer queue: producers await put, consumers await get.
07:22
Coroutines are objects, not executed immediately
Fundamental concept: async def returns a coroutine object; you must await it to run.
00:51Await yields control to event loop
Core mechanism enabling concurrency: tasks pause cooperatively.
01:21gather runs tasks concurrently
Key performance win: total time equals slowest task, not sum.
02:53Timeouts with wait_for
Essential for production reliability: prevents hanging on slow operations.
05:46Semaphore limits concurrency
Prevents overwhelming servers; critical for rate-limited APIs.
06:02[00:00] Your program freezes for a full second
[00:02] on every network call. Your loop
[00:04] processes earl painfully slow. Every
[00:08] blocking call weighs time just sitting
[00:10] and waiting. I am Mahas. Today in
[00:13] episode 25, async Python, you will learn
[00:17] how to run thousands of operations
[00:19] concurrently without threads. We will
[00:21] cover async defaf and await. How co-
[00:24] routines actually work. Assentio.run and
[00:28] the event loop. Assessio.Gather for
[00:30] running tasks concurrently.
[00:32] Assencio.create
[00:34] task for scheduling background work.
[00:36] Async context managers using dunder
[00:38] enter and dunder exit and real
[00:40] production patterns timeouts semaphors
[00:43] and async iteration. By the end you will
[00:46] have a full concurrent API fetcher with
[00:48] a semaphore rate limit. Let's go. A
[00:51] co-ine is a function defined with async
[00:54] defaf. Calling it does not run the code.
[00:57] It creates a co-outine object. Let's
[00:59] understand what happens under the hood.
[01:01] Look at the code. On the left, we define
[01:03] a regular function fetch data. Calling
[01:07] fetch data executes immediately and
[01:10] returns a value. On the right, we define
[01:13] the same function with async defaf.
[01:15] Calling fetch data now returns a
[01:18] co-outine object. Nothing is run yet. To
[01:21] actually run it, you need a wait. But a
[01:23] wait only works inside another async
[01:26] function. Inside the corine, a wait
[01:28] essenti. pauses this task and lets the
[01:32] event loop run other code. When the
[01:34] sleep finishes, execution resumes
[01:37] exactly where it left off. Async defaf
[01:40] creates a co-ine. A wait is what
[01:42] actually runs it and gives you the
[01:44] result. This pause and resume mechanism
[01:46] is the foundation of every async pattern
[01:49] in Python. Every async program needs an
[01:52] entry point. That's essenti.run. Look at
[01:55] the code. We define an async function
[01:58] called main. Inside main, we print
[02:00] hello. Then a weight essenti
[02:03] of 1 second. This is non-blocking. The
[02:06] event loop is free during this weight.
[02:09] Then we print world. At the bottom,
[02:12] essenti
[02:15] is the entry point. It creates a brand
[02:18] new event loop. runs the main co-
[02:20] routine until it completes and then
[02:22] closes the loop automatically. You call
[02:25] essentio.run
[02:26] exactly once at the top level of your
[02:29] program never inside another corine and
[02:32] never nested. The event loop is the
[02:34] engine that schedules every corine call
[02:37] back and timer. Asiosleep does not block
[02:41] the thread. It tells the loop come back
[02:43] to me later. This is the core mental
[02:46] model. One loop, many co- routines,
[02:49] cooperative pausing. Now let's run
[02:51] multiple co- routines at the same time.
[02:53] Look at the code on the left. Sequential
[02:56] await. We await fetch of one, then fetch
[02:59] of two, then fetch of three. Each takes
[03:01] 1 second and a wait blocks until each
[03:04] finishes before starting the next. Total
[03:07] time about 3 seconds. On the right,
[03:11] concurrent with Asencio.
[03:13] We pass all three co- routines to
[03:15] essentiate
[03:18] the whole thing at once. All three start
[03:21] immediately and run concurrently. Total
[03:24] time about 1 second. The time of the
[03:27] slowest task, not the sum.
[03:29] Assentio.gather
[03:31] returns the results as a list in in the
[03:33] same order you pass the corines in,
[03:36] regardless of which one finishes first.
[03:38] This is the single biggest performance
[03:40] win in async code. Independent IO
[03:43] operations should almost always run with
[03:46] gather not sequential await. Asio.create
[03:50] task lets you start a co- routine
[03:52] running in the background immediately
[03:54] without waiting for it. Look at the
[03:56] code. We define a worker function that
[03:59] sleeps for a delay then prints done.
[04:01] Inside main, we call essentio.create
[04:04] task for worker A with a 2-cond delay.
[04:08] and again for worker B with a 1second
[04:10] delay. Both lines return immediately.
[04:13] The tasks are scheduled but main keeps
[04:15] running. We print both started right
[04:18] away. Then we await T1 and await T2 to
[04:21] collect their results. Even though A was
[04:23] created first, B finishes first because
[04:26] B's delay is shorter. The scheduling
[04:29] order is not the completion order.
[04:31] Create underscore task is how you fire
[04:34] off work now and collect the result
[04:36] later. Perfect for background jobs,
[04:39] logging or fire and forget operations
[04:41] you still want to track. Some resources
[04:43] need asynchronous setup and cleanup
[04:46] database connections, network sessions,
[04:48] locks. That's what async with is for.
[04:51] Look at the code. We define an async
[04:54] connection class. Dunder enter is an
[04:57] async method. It awaits connect_b
[05:00] to open the connection and returns it.
[05:03] Dunder exit is also async. It awaits the
[05:06] connections close method to clean up
[05:08] inside main async with async connection
[05:11] open perin close pin as con gives us the
[05:15] connection object. We await conexecute
[05:18] inside the block when the block exits
[05:21] even if an exception occurs. Dunder exit
[05:23] runs automatically and the connection
[05:26] closes. Async with is the asynchronous
[05:28] version of the regular with statement.
[05:31] same guarantee of cleanup, but every
[05:33] step can be in non-blocking await.
[05:35] You'll see this pattern in database
[05:37] drivers, HTTP client sessions, and
[05:41] distributed locks. Let's look at three
[05:43] productionready async patterns. First,
[05:46] timeouts with essentio.we_4.
[05:49] Wrap any co- routine with a timeout in
[05:52] seconds. If it doesn't finish in time,
[05:55] essenti
[05:56] error is raised. Catch it and return a
[05:59] fall back. Second limiting concurrency
[06:02] with essentio.seaphore.
[06:04] Create a semaphore with a fixed limit.
[06:06] Then async with sim before each
[06:09] operation only that many operations run
[06:12] at once. Everything else waits its turn.
[06:14] This prevents overwhelming a server with
[06:17] thousands of simultaneous requests.
[06:19] Third, async iteration with async 4. An
[06:23] async generator yields values one at a
[06:25] time awaiting between each. Perfect for
[06:28] streaming lines from a file or
[06:30] pageionated API results. All three
[06:33] patterns combine, a semaphore limited
[06:35] timeout protected async generator is the
[06:38] backbone of any serious data pipeline.
[06:41] Asio ships with several essential tools.
[06:44] Let's cover the four most important
[06:46] ones. First, as Entios sleep, a
[06:50] non-blocking pause. It yields control
[06:52] back to the event loop instead of
[06:54] freezing the thread. Second,
[06:57] essentio.weight_4
[06:59] runs a co- routine with a timeout
[07:02] raising timeout error if it's too slow.
[07:04] Third essentio.task
[07:07] group available in Python 311 and later.
[07:10] Structured concurrency create tasks
[07:13] inside the group and if any task raises
[07:16] all other tasks are automatically
[07:18] canled. Fourth, essentio.q an async safe
[07:22] producer consumer queue. Producers
[07:24] await, put, consumers await, get. These
[07:27] four tools handle pausing, timeouts,
[07:30] structure concurrency, and inter task
[07:32] communication. Use them before reaching
[07:35] for threads or third party async
[07:37] libraries. Our mini project, a
[07:40] concurrent API fetcher with a semaphore
[07:42] rate limit. This is the pattern used in
[07:45] every production data pipeline. Look at
[07:47] the code. We define an async fetch
[07:50] function that takes a session, a URL,
[07:52] and a semaphore. Async with sim limits
[07:56] how many requests run at once. Inside
[07:59] async with session get awaits the
[08:01] response and returns the JSON. Fetch_all
[08:05] creates a semaphore with a given limit,
[08:07] opens one a client session, builds a
[08:10] list of fetch co- routines, one per URL,
[08:13] and awaits a cinio. rather on all of
[08:15] them at once. We call Asenio.run
[08:19] with limit equals 10, meaning up to 10
[08:21] requests run concurrently. The rest Q
[08:24] automatically. This single pattern can
[08:26] fetch thousands of Earls, respect a
[08:29] server's rate limits, and finish in a
[08:31] fraction of the time sequential code
[08:32] would take. Your challenge, build an
[08:35] async pipeline from scratch. Step one,
[08:38] write an async fetch user function that
[08:41] takes an ID, awaits a centio. To
[08:44] simulate network delay, and returns a
[08:47] fake user dict. Step two, use
[08:49] essentio.gather to fetch 10 users
[08:52] concurrently and print the total elapse
[08:54] time. Step three, wrap the gather call
[08:57] with an essentio.
[08:59] of three so only three fetches run at
[09:02] once. Compare the timing. Step four,
[09:05] write an async context manager called
[09:07] timer that prints elapse time on exit
[09:10] using dunder enter and dunder exit. Step
[09:13] five, combine everything into one async
[09:16] main function and run it with
[09:17] essentio.run. Paste your full pipeline
[09:20] and the timing output in the comments. I
[09:23] read every single one. Let's recap what
[09:25] you learned today. Async defaf defines a
[09:28] co- routine. Calling it returns an
[09:30] object it doesn't run yet. Await runs a
[09:33] co- routine and pauses until the result
[09:36] is ready, yielding control to the event
[09:38] loop. Assentio.run is the entry point.
[09:42] It creates runs and closes the event
[09:44] loop call at once. Assencio.gather runs
[09:48] many corines concurrently. Total time is
[09:51] roughly the slowest one, not the sum.
[09:54] Assentio.create
[09:56] task schedules work immediately. Await
[09:59] it later for the result. Async width,
[10:02] dunder enter, and dunder exit handle
[10:04] asynchronous setup and cleanup. Wait
[10:07] underscore for ads timeouts and
[10:09] semaphore limits concurrency. The mini
[10:12] project built a concurrent API fetcher
[10:14] with a rate limiting semaphore. Next
[10:16] episode, context managers with dunder
[10:19] enter, dunder exit, and context slip.
[10:23] Subscribe so you don't miss it. See you
[10:25] tomorrow. Async mastered. Your Python
[10:28] code now runs concurrently without
[10:31] blocking on a single IO call. Subscribe
[10:33] for the next episode. Drop your async
[10:36] pipeline in the comments. I am Aas. See
[10:39] you in episode 26.
⚡ Saved you 0h 10m reading this? Transcribe any YouTube video for free — no signup needed.