liveBook · Manning

Checkout_customer

As explained in Python Concurrency with asyncio

checkout_customer is a book-local coroutine function that processes one supermarket customer and marks the customer's queue item complete.

checkout_customer is an asyncio coroutine that represents one supermarket cashier. It repeatedly takes a customer from a queue, processes each product with simulated asynchronous checkout time, and calls queue.task_done() when the customer is finished. section 12.1

Its workflow connects queue coordination with per-customer processing:

  • Retrieve a customer using queue.get_nowait(), or await queue.get() in the coroutine-based variant. section 12.1
  • Loop through the customer's products and await asyncio.sleep(product.checkout_time) to simulate scanning. section 12.1
  • Call queue.task_done() after checkout so queue.join() can recognize completed work. section 12.1
Listing 12.1 A supermarket checkout queue
import asyncio
from asyncio import Queue
from random import randrange
from typing import List
 
 
class Product:
    def __init__(self, name: str, checkout_time: float):
        self.name = name
        self.checkout_time = checkout_time
 
 
class Customer:
    def __init__(self, customer_id: int, products: List[Product]):
        self.customer_id = customer_id
        self.products = products
 
 
async def checkout_customer(queue: Queue, cashier_number: int):
    while not queue.empty():                                              #1
        customer: Customer = queue.get_nowait()
        print(f'Cashier {cashier_number} '
              f'checking out customer '
              f'{customer.customer_id}')
        for product in customer.products:                                 #2
            print(f"Cashier {cashier_number} "
                  f"checking out customer "
                  f"{customer.customer_id}'s {product.name}")
            await asyncio.sleep(product.checkout_time)
        print(f'Cashier {cashier_number} '
              f'finished checking out customer '
              f'{customer.customer_id}')
        queue.task_done()
 
 
async def main():
    customer_queue = Queue()
 
    all_products = [Product('beer', 2),
                    Product('bananas', .5),
                    Product('sausage', .2),
                    Product('diapers', .2)]
 
    for i in range(10):                                                   #3
        products = [all_products[randrange(len(all_products))]
                    for _ in range(randrange(10))]
        customer_queue.put_nowait(Customer(i, products))
    cashiers = [asyncio.create_task(checkout_customer(customer_queue, i)) #4
                for i in range(3)]                                        #4
    await asyncio.gather(customer_queue.join(), *cashiers)
 
asyncio.run(main())

Shows the complete supermarket queue, cashier workers, customer processing loop, and completion signaling. section 12.1

How Python Concurrency with asyncio covers it

How deep it goes
Explains retrieval, product iteration, simulated delays, and task accounting, then contrasts nonblocking and awaiting queue methods.
Examples
Uses Product and Customer objects, random product baskets, three cashier tasks, and simulated checkout output.
What it assumes
Assumes basic Python classes and async functions while teaching queue workers and unfinished-task accounting through the example.
What you can do after
Build it from scratch as an asyncio queue worker that processes items and signals completion correctly.
How it connects
Connects asyncio Queue, coroutine, worker tasks, asyncio.sleep(), queue.task_done(), and queue.join().

This explainer was generated by Manning's knowledge graph from the text of Python Concurrency with asyncio. The section links point to the parts of the book it draws on.