- Home
- Introduction
- Environment Setup
- Concurrency vs Parallelism
- System & Memory Architecture
- Threads
- Implementation of Threads
- Synchronizing Threads
- Threads Intercommunication
- Testing Thread Applications
- Debugging Thread Applications
- Benchmarking & Profiling
- Pool of Threads
- Pool of Processes
- Multiprocessing
- Processes Intercommunication
- Event-Driven Programming
- Reactive Programming
Python Resources
Concurrency in Python - Event Driven Programming
Event-driven programming focuses on events. Eventually, the flow of program depends upon events. Until now, we were dealing with either sequential or parallel execution model but the model having the concept of event-driven programming is called asynchronous model. Event-driven programming depends upon an event loop that is always listening for the new incoming events. The working of event-driven programming is dependent upon events. Once an event loops, then events decide what to execute and in what order. Following flowchart will help you understand how this works −
Python Module - Asyncio
Asyncio module was added in Python 3.4 and it provides infrastructure for writing single-threaded concurrent code using co-routines. Following are the different concepts used by the Asyncio module −
The event loop
Event-loop is a functionality to handle all the events in a computational code. It acts round the way during the execution of whole program and keeps track of the incoming and execution of events. The Asyncio module allows a single event loop per process. Followings are some methods provided by Asyncio module to manage an event loop −
loop = get_event_loop() − This method will provide the event loop for the current context.
loop.call_later(time_delay,callback,argument) − This method arranges for the callback that is to be called after the given time_delay seconds.
loop.call_soon(callback,argument) − This method arranges for a callback that is to be called as soon as possible. The callback is called after call_soon() returns and when the control returns to the event loop.
loop.time() − This method is used to return the current time according to the event loops internal clock.
asyncio.set_event_loop() − This method will set the event loop for the current context to the loop.
asyncio.new_event_loop() − This method will create and return a new event loop object.
loop.run_forever() − This method will run until stop() method is called.
Example - Calling a async method
The following example helps in printing hello world by using the run() method to call a method in async way.
import asyncio
async def main():
print("Hello World")
# Run the async method
asyncio.run(main())
Output
Hello World
Futures
This is compatible with the concurrent.futures.Future class that represents a computation that has not been accomplished. There are following differences between asyncio.futures.Future and concurrent.futures.Future −
result() and exception() methods do not take a timeout argument and raise an exception when the future isnt done yet.
Callbacks registered with add_done_callback() are always called via the event loops call_soon().
asyncio.futures.Future class is not compatible with the wait() and as_completed() functions in the concurrent.futures package.
Example - Usage of Asyncio Future
The following is an example that will help you understand how to use asyncio.futures.future class.
main.py
import asyncio
async def MyOperation(future):
await asyncio.sleep(2)
future.set_result('Completed')
async def main():
# get running loop and create a future object
loop = asyncio.get_running_loop()
future = loop.create_future()
# create a task and complete the future
asyncio.create_task(MyOperation(future))
# Await for the future to complete
print("Waiting for future to complete...")
result = await future
# once future is done, print the result.
print(f"Future result: {result}")
# Run the main method
if __name__ == "__main__":
asyncio.run(main())
Output
Run the code and verify the output −
Waiting for future to complete... Future result: Completed
Coroutines
The concept of coroutines in Asyncio is similar to the concept of standard Thread object under threading module. This is the generalization of the subroutine concept. A coroutine can be suspended during the execution so that it waits for the external processing and returns from the point at which it had stopped when the external processing was done. The following two ways help us in implementing coroutines −
Example - async def function()
This is a method for implementation of coroutines under Asyncio module. Following is a Python script for the same −
main.py
import asyncio
async def MyOperation():
print("First Coroutine")
# Run the async method
asyncio.run(MyOperation())
Output
Run the code and verify the output −
First Coroutine
Example - Tasks
This subclass of Asyncio module is responsible for execution of coroutines within an event loop in parallel manner. Following Python script is an example of processing some tasks in parallel.
main.py
import asyncio
import time
async def Task_ex(n):
time.sleep(1)
print("Processing {}".format(n))
async def Generator_task():
for i in range(10):
asyncio.ensure_future(Task_ex(i))
print("Tasks Completed")
asyncio.sleep(2)
# Run the async method
asyncio.run(Generator_task())
Output
Run the above code and verify the output −
Tasks Completed Processing 0 Processing 1 Processing 2 Processing 3 Processing 4 Processing 5 Processing 6 Processing 7 Processing 8 Processing 9
Transports
Asyncio module provides transport classes for implementing various types of communication. These classes are not thread safe and always paired with a protocol instance after establishment of communication channel.
Following are distinct types of transports inherited from the BaseTransport −
ReadTransport − This is an interface for read-only transports.
WriteTransport − This is an interface for write-only transports.
DatagramTransport − This is an interface for sending the data.
BaseSubprocessTransport − Similar to BaseTransport class.
Followings are five distinct methods of BaseTransport class that are subsequently transient across the four transport types −
close() − It closes the transport.
is_closing() − This method will return true if the transport is closing or is already closed.transports.
get_extra_info(name, default = none) − This will give us some extra information about transport.
get_protocol() − This method will return the current protocol.
Protocols
Asyncio module provides base classes that you can subclass to implement your network protocols. Those classes are used in conjunction with transports; the protocol parses incoming data and asks for the writing of outgoing data, while the transport is responsible for the actual I/O and buffering. Following are three classes of Protocol −
Protocol − This is the base class for implementing streaming protocols for use with TCP and SSL transports.
DatagramProtocol − This is the base class for implementing datagram protocols for use with UDP transports..
SubprocessProtocol − This is the base class for implementing protocols communicating with child processes through a set of unidirectional pipes.