Python Event Loop

Summary: in this tutorial, you’ll learn about the Python event loop and how Python uses it to achieve the concurrency model using a single thread.

Introduction to the Python event loop

Concurrency means multiple tasks can run at the same time. The asyncio built-in package allows you to run tasks concurrently using a single thread.

To achieve a single-threaded concurrency model, the asyncio package uses a construct called an event loop. To understand how the event loop works, let’s take an example of writing data into a file.

When writing data to a file, you perform the following steps:

  • Open the file
  • Write data to a file and wait for it to be completed
  • Close the file

In this flow, the second task is blocking. Internally, it works like this:

  • First, the function, which writes data to the file, sends data to the operating system (OS).
  • Second, the OS takes over and starts writing data to the file.
  • Third, the OS notifies the program once it completes writing the file.

To manage the notifications, the different OS uses different event notification systems. For example:

OSEvent Notification System
Linuxepoll
WindowsI/O completion port (IOCP)
macOSkqueue

These event notification systems allow us to achieve concurrency using a single thread. While the program waits for the OS to notify the completion, it can run other code.

In the single-threaded concurrency model, we have only one thread executing Python code at any time. When we encounter an I/O bound task, we hand it over to the operating system’s event notification system and run other code.

When the I/O bound task completes, we can resume the task that was waiting for the result and execute the code that follows the I/O bound task.

To keep track of I/O-bound tasks that are waiting for results, the asyncio package uses an event loop. The following picture illustrates how the event loop work:

How it works.

  • First, the main thread submits tasks to a task queue.
  • Second, the event loop constantly monitors the task queue and runs the task until it counters I/O tasks. In this case, the event loop pauses the task and hands it over to the OS.
  • Third, check for the completed IO tasks. If the task is completed, the OS will notify the program. The event loop then runs the unpaused tasks.

These steps are repeated until the task queue is empty.

Prior to Python 3.7, you need to create an event loop and run tasks manually. Fortunately, after Python 3.7, the asyncio package provides some functions that allow you to automatically manage the event loop so you don’t need to deal with low-level API.

In the next tutorial, you’ll learn how to define coroutines using the async keyword and pause them using the await keyword.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *