Skip to content

Instantly share code, notes, and snippets.

@dissolved
Last active December 9, 2021 23:00
Show Gist options
  • Save dissolved/b41f7ceffd49c83efc474c90c53592ed to your computer and use it in GitHub Desktop.
Save dissolved/b41f7ceffd49c83efc474c90c53592ed to your computer and use it in GitHub Desktop.
Python Async/Await Introduction

Blocking vs Non-Blocking

A real world example

Let's say you have the following chores to do:

  • Balance your checkbook
  • Do 3 loads of laundry
  • Cook a pie

If we did all of these tasks synchronously it would take a very long time. Balancing the checkbook might take 30 minutes, each load of laundry will need to go through a wash cycle (30 minutes), and a dry cycle (45 minutes), and cook a pie (15 minutes prep, 30 minutes baking). If we blocked on each task, it would go like this:

  • 30 minutes checkbook
  • 30 minutes x 3 loads = 90 minutes washing laundry
  • 45 minutes x 3 loads = 135 minutes drying laundry
  • 45 minutes making the pie

That's 5 hours if I did my math correctly! But we don't need to block (aka wait) for some of these processes. We can get them started and move on to another task. Let's say each load of wash is broken down as 5 minutes blocking and 25 minutes non-blocking, drying is 5 minutes blocking and 40 minutes non-blocking and the pie is 15 minutes blocking and 30 minutes non-blocking.

  • 5 minutes load first wash
  • 15 minutes pie prep
  • 10 minutes on the checkbook (20 remain)
  • 5 minutes load dryer
  • 5 minutes load 2nd wash
  • 10 minutes on the checkbook (10 remain)
  • (remove the pie, let's call this 0 minute task for simplicity)
  • 10 minutes on the checkbook
  • 15 minutes idle (but we could be doing something useful)
  • 5 minutes 2nd dryer load
  • 5 minutes last wash
  • 40 minutes idle
  • 5 minutes last dryer load
  • 40 minutes idle

We did it all in under 3 hours, and we had lots of idle time to watch our favorite HBO series.

That is all async/await really is. You aren't actually doing more than one thing at a time, but you can go on to do other things while something that doesn't need your attention is working.

# A Synchronous Approach to Our Chores
from time import asctime, sleep
from datetime import datetime
def do_the_laundry():
for _ in range(3):
wash_laundry()
dry_laundry()
def wash_laundry():
load_washer()
wait_for_washer()
def load_washer():
display("loading washer")
sleep(1)
def wait_for_washer():
display("clothes washing")
sleep(5)
def dry_laundry():
load_dryer()
wait_for_dryer()
def load_dryer():
display("loading dryer")
sleep(1)
def wait_for_dryer():
display("clothes drying")
sleep(8)
def make_a_pie():
prep_pie()
bake_pie()
def prep_pie():
display("prepping a pie")
sleep(3)
def bake_pie():
display("pie is baking")
sleep(6)
def work_on_checkbook():
display("balancing checkbook")
sleep(6)
def display(text):
print(f"{asctime()}: {text}")
start = datetime.now()
do_the_laundry()
work_on_checkbook()
make_a_pie()
finish = datetime.now()
print(f"The total elapsed time is {finish - start}")
import asyncio
from datetime import datetime
from time import asctime, sleep
async def do_the_laundry():
for _ in range(3):
await wash_laundry()
await dry_laundry()
async def wash_laundry():
load_washer()
await wait_for_washer()
def load_washer():
display("loading washer")
sleep(1)
async def wait_for_washer():
display("πŸ‘”πŸ‘šπŸ‘– clothes washing")
await asyncio.sleep(5)
display("πŸ’¦ Ready to dry πŸ‘”πŸ‘šπŸ‘– ")
async def dry_laundry():
load_dryer()
await wait_for_dryer()
def load_dryer():
display("loading dryer")
sleep(1)
async def wait_for_dryer():
display("πŸ‘”πŸ‘šπŸ‘– clothes drying")
await asyncio.sleep(8)
display("🧺 dry")
async def make_a_pie():
prep_pie()
await bake_pie()
def prep_pie():
display("prepping a πŸ₯§")
sleep(3)
display("πŸ₯§ ready to bake")
async def bake_pie():
display("πŸ₯§ is baking")
await asyncio.sleep(6)
display("πŸ₯§ is READY TO EAT!!!")
async def work_on_checkbook():
# break this task into 3
for n in range(3):
display(f"balancing checkbook {n}")
sleep(1.99)
await asyncio.sleep(.01)
def display(text):
print(f"{asctime()}: {text}")
async def do_chores():
laundry_task = asyncio.create_task(do_the_laundry())
checkbook_task = asyncio.create_task(work_on_checkbook())
pie_task = asyncio.create_task(make_a_pie())
await asyncio.gather(laundry_task, checkbook_task, pie_task)
if __name__ == "__main__":
start = datetime.now()
asyncio.run(do_chores())
finish = datetime.now()
print(f"The total elapsed time is {finish - start}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment