TubeSum ← Transcribe a video

Python Async Await EXPLAINED | Run 1000 Tasks on ONE Thread | asyncio Tutorial | Ep 25

0h 10m video Transcribed Jun 15, 2026
Intermediate 5 min read For: Python developers familiar with basic syntax who want to learn asynchronous programming for I/O-bound tasks.
2
Views
2
Likes
1
Comments
0
Dislikes
150.0%
📊 Average

AI Summary

This 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.

[00:51]
Coroutines are defined with async def

Calling an async function returns a coroutine object, not executing the code immediately. To run it, you need await.

[01:21]
Await pauses and yields control

Inside a coroutine, await pauses the current task and lets the event loop run other code. When the awaited operation finishes, execution resumes.

[01:52]
asyncio.run is the entry point

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.

[02:53]
asyncio.gather runs tasks concurrently

Pass multiple coroutines to gather; they start immediately and run concurrently. Total time equals the slowest task, not the sum.

[03:50]
asyncio.create_task for background work

Schedules a coroutine to run immediately without waiting. Use await later to collect the result.

[04:51]
Async context managers with __aenter__ and __aexit__

Define async methods for setup and cleanup. Use 'async with' to ensure non-blocking resource management.

[05:46]
Timeouts with asyncio.wait_for

Wrap a coroutine with a timeout. If it doesn't finish in time, asyncio.TimeoutError is raised.

[06:02]
Limiting concurrency with asyncio.Semaphore

Create a semaphore with a fixed limit. Use 'async with sem' before each operation to control how many run at once.

[06:19]
Async iteration with async for

An async generator yields values one at a time, awaiting between each. Useful for streaming data.

[07:40]
Mini project: concurrent API fetcher

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.

Clickbait Check

95% Legit

"Title accurately promises to explain async/await and run many tasks on one thread; the video delivers exactly that."

Mentioned in this Video

Tutorial Checklist

1 08:38 Write an async fetch_user function that takes an ID, awaits asyncio.sleep to simulate delay, and returns a fake user dict.
2 08:49 Use asyncio.gather to fetch 10 users concurrently and print total elapsed time.
3 08:57 Wrap the gather call with an asyncio.Semaphore of 3 so only three fetches run at once. Compare timing.
4 09:05 Write an async context manager called Timer that prints elapsed time on exit using __aenter__ and __aexit__.
5 09:13 Combine everything into one async main function and run it with asyncio.run.

Study Flashcards (12)

What does calling an async def function return?

easy Click to reveal answer

It returns a coroutine object, not executing the code immediately.

00:51

What does await do inside a coroutine?

easy Click to reveal answer

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?

easy Click to reveal answer

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?

medium Click to reveal answer

gather runs all coroutines concurrently; total time is the slowest task, not the sum.

02:53

What is the purpose of asyncio.create_task?

medium Click to reveal answer

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?

medium Click to reveal answer

__aenter__ and __aexit__ (both async methods).

04:51

How do you add a timeout to a coroutine?

medium Click to reveal answer

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?

medium Click to reveal answer

Use asyncio.Semaphore with a fixed limit and 'async with sem' before each operation.

06:02

What is the syntax for async iteration?

easy Click to reveal answer

async for item in async_generator: ...

06:19

What does asyncio.sleep do?

easy Click to reveal answer

It yields control back to the event loop for a non-blocking pause.

06:44

What is asyncio.TaskGroup (Python 3.11+)?

hard Click to reveal answer

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?

medium Click to reveal answer

Async-safe producer-consumer queue: producers await put, consumers await get.

07:22

💡 Key Takeaways

⚖️

Coroutines are objects, not executed immediately

Fundamental concept: async def returns a coroutine object; you must await it to run.

00:51
🔧

Await yields control to event loop

Core mechanism enabling concurrency: tasks pause cooperatively.

01:21
🔧

gather runs tasks concurrently

Key performance win: total time equals slowest task, not sum.

02:53
🔧

Timeouts with wait_for

Essential for production reliability: prevents hanging on slow operations.

05:46
🔧

Semaphore limits concurrency

Prevents overwhelming servers; critical for rate-limited APIs.

06:02

✂️ Creator Tools: Viral Hooks

AI-generated clip ideas for Shorts based on the transcript

Your Code Freezes? Fix It with Async!

45s

Immediately hooks viewers who struggle with slow code by promising a solution to freezing network calls.

▶ Play Clip

Async Def vs Regular Def: The Key Difference

60s

Clearly explains a fundamental concept that many Python developers misunderstand, making it highly educational.

▶ Play Clip

3x Faster Code with asyncio.gather

60s

Demonstrates a dramatic performance improvement (3 seconds to 1 second) that viewers can immediately apply.

▶ Play Clip

3 Production Async Patterns You Need

60s

Provides actionable, real-world patterns (timeouts, semaphores, async iteration) that solve common problems.

▶ Play Clip

Build a Concurrent API Fetcher in 60 Seconds

60s

Shows a complete mini-project that viewers can build themselves, with a clear challenge to engage them.

▶ Play Clip

[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.