Python – Asynchronous Programming

The asyncio module allows for asynchronous input and output, event loops, single threading coronoutines and tasks.

Base Event Loop

In asyncio the event loop is the central execution device.

With it you can:

  • Register, execute, and cancel delayed callouts.
  • For various kinds of communication create client and server transports
  • Launching subprocesses associated with transports
  • Delegating function calls to a pool of threads

Coroutines

Coroutines with asyncio may be implemented using the async def statement or by using generators.

Generator-based coroutines should be decorated with @asyncio.coroutine. The decororator enables compatibility with async def coroutines. Generator-based coroutines use the yeild from syntax.

Here is a simple example of an asyncrhonous countdown using a generator-based coroutine:

import asyncio

@asyncio.coroutine
def my_coroutine(task_name, seconds_to_sleep=3):  

     print('{0} sleeping for: {1} seconds'.format(task_name, seconds_to_sleep)) 
     yield from asyncio.sleep(seconds_to_sleep) 
     print('{0} is finished'.format(task_name))

loop = asyncio.get_event_loop()
tasks = [ 
    my_coroutine('task1',4), 
    my_coroutine('task2',3), 
    my_coroutine('task3',2)]

loop.run_until_complete(asyncio.wait(tasks))
loop.close()

 

  • A coutroutine can be suspended and then returns the future’s result or rasises an exception which can be propagated. Syntax can be represented as: result yeild from future
  • The coroutine expression must call another to another coroutine. result = yield from coroutine waits for another coroutine to produce a result or exception.
  • return expression – produces a result to the coroutine that is waiting for the one using yeild from or await
  • raise exception – raises an exception from the in the coroutine that is waiting for the on using yeild from or await

Beginner hello world script:

import asyncio

async def hello_world():  
     print("hello world!")

loop = asyncio.get_event_loop()
#blocking call which returns the hello_world() 
coroutine is doneloop.run_until_complete(hello_world())
loop.close()

Coroutine displaying the current date/time for 5 seconds:

import asyncio
import datetime

async def display_date(loop): 

    end_time = loop.time() + 5.0 
    while True:  
         print(datetime.datetime.now()) 
         if (loop.time() + 1.0) >= end_time:  
             break 
        await asyncio.sleep(1)

loop = asyncio.get_event_loop()
# Blocking call which returns the display_date() coroutine is done
loop.run_until_complete(display_date(loop))
loop.close()

Chained coroutines:

import asyncio

async def compute(x,y):  
    print("Compute %s + %s ..." % (x,y)) 
    await asyncio.sleep(1.0) return x + y 

async def print_sum(x,y):  
    result = await compute(x,y) print("%s + %s = %s" % (x,y,result))

loop = asyncio.get_event_loop()
loop.run_until_complete(print_sum(1,2))
loop.close()