Yes but why does it function like that? I thought the speed limit is based on process weight
For I/O-bound tasks, majority of the time is spent waiting - you might send off a 1KB request and it'll take 400ms for the server to receive, process, and send back a response, during which your program isn't doing anything else. Synchronous functions usually wait out that time, or in other words "block", so they're able to return that response to you: ```py response = requests.get(...) # ^^^^^^^^^^^^^^^^^ # Function blocks for response print(response.content)``` But if you've heard of non-blocking sockets, that is the operating system providing a way to send/receive data over your network *without* blocking. `asyncio` combines those APIs with async/await coroutines (functions that can stop and resume) to let you resume some other functions in the same thread, until it gets back a response and it can resume the original function that made the request. (see also ) In contrast, CPU-bound tasks require your thread to run a bunch of instructions (e.g. processing images). In these cases, asyncio can't complete them any faster than a regular, synchronous program because asyncio is single-threaded. You would need to share that workload across multiple threads and/or processes so your CPU can run those instructions in parallel.