4 ms·
The coroutine approach shines for complex business-logic. Consider this example algorithm, of several async steps, 1. Download a file into memory 2. Email a
by cturner 3y ago
The coroutine approach shines for complex business-logic.
Consider this example algorithm, of several async steps,
1. Download a file into memory
2. Email a link to a review web page.
3. Wait for the user to review.
4. Upload the file to a partner.
5. Update a database.
You could implement this as callbacks. Callback from each step leads to the next being triggered. Downside - your business logic is spread across all the callbacks. You could mitigate this somewhat by defining a class with one method for each step, with those methods being defined in the same visual order as the algorithm. Then have each callbacks call a method. (The article shows something different but similar with its Command autoCommand pattern.)
Tricks like this only go so far. Imagine if the reviewer user had a choice of pressing 'approve' or 'reject' on the webserver interface, with the algorithm changing depending on their answer. How do you now represent the business logic so the programmer can follow it?
Such changes are easy in coroutines. Here is the algorithm with that variation in coroutine code,
async def review(review_id, url):
file_content = await download_large_file(url, review_id)
ws_review_id = await create_webserver_review_page(file_content)
await email_the_user(ws_review_id)
result = await get_webserver_user_response(ws_review_id)
if result:
await upload_to_partner(file_content)
else:
await alert_failure(review_id, file_content)
await update_database(review_id, ws_review_id, result)
You state that callback code gives you easy visibility to what actually happens - yes, they do. When you read callback code, it is natural to follow business-logic to system calls. Coroutine tends towards code of layered business-logic and abstraction.
- mgaunard 3y agoJust use lambdas, that makes the sequence local.