Asynchronous Programming – Python Exercise

Learning Goals

  • Software design approaches and patterns, to identify reusable solutions to commonly occurring problems
  • Apply an appropriate software development approach according to the relevant paradigm (for example object oriented, event driven or procedural)

Programs Used

Part 1 – Concurrency

The below piece of code uses the result of two independent coroutines functions:

import asyncio

async def task_completer(delay, task):
    print(f"number {task} is loading...")
    await asyncio.sleep(delay)
    print(f"...number {task} has loaded")
    return task

async def main():
    p1 = task_completer(1, 4)
    p2 = task_completer(2, 8)
    
    result1 = await p1
    result2 = await p2
    
    print(result1 + result2)

asyncio.run(main())
  • Make these two coroutine functions run concurrently by converting them to tasks
  • What is the difference between awaiting the two coroutine functions and converting them to tasks?

Part 2 – Handling errors with concurrency

The following two functions need to be executed in sequence but occasionally throw an error:

import asyncio
import random

async def p1():
    await asyncio.sleep(0.5)
    if random.random() < 0.5:
        return "success"
    else:
        raise Exception("promise rejected")

async def p2():
    await asyncio.sleep(1)
    if random.random() < 0.5:
        return "success"
    else:
        raise Exception("error thrown")

async def main():
    result1 = await p1()
    result2 = await p2()
    print(f"result 1 was a {result1}")
    print(f"result 2 was a {result2}")

asyncio.run(main())
  • Make sure that all errors are caught.
  • Can your code disambiguate between the two errors? If not, how would you modify it so that it can?
  • If you were to run the couroutines in parallel using asyncio.gather and change the couroutines to always return an error, which error(s) do you expect to see in the exception block? Once you have an answer, change the code to verify your assumption.
  • Use tasks to run both functions concurrently, but make sure that it waits until both have completed.

Part 3 – Concurrency with Busboard

Clone the repository and open in your IDE. This repository contains half of the BusBoard exercise from the bootcamp. Just like the app you made, it will prompt the user for a postcode and will return the bus routes heading to that area. Check that you can run the app by running poetry install, followed by poetry run start. Your goal is to utilise concurrency with Busboard.

  1. Update console_runner.py and __init__.py so that it uses async/await instead of functions (hint: you may need to use an event loop run_in_executer to run a function in another thread).
  2. Make sure you catch all errors and that you are able to disambiguate between error cases.

Remember to commit early and often!