The Evolution and Principles of Coroutines: From COBOL to Modern Languages
This article traces the historical origins of coroutines from early COBOL compiler challenges, explains their cooperative execution model, compares them with thread scheduling, and reviews how modern languages like Python, C++ and Go implement coroutine support to improve IO‑bound performance.
The article begins with a personal motivation to clarify the vague understanding of coroutines after years of backend development in C/C++, Python, and Go.
It explains that a coroutine is a broad design concept whose concrete implementations vary, and that the idea predates threads, dating back to the 1950s with the COBOL language.
Historical context is provided: early COBOL compilers in the late 1950s faced severe hardware constraints, such as tape‑based storage that prevented one‑pass compilation, leading to multi‑pass designs where lexical and syntactic analyses had to rewind the tape repeatedly.
Melvin Conway’s cooperative solution interleaved lexical and syntactic analysis, allowing the compiler to yield control between the two phases while preserving state—essentially the earliest coroutine concept.
The article discusses why coroutines remained obscure, noting their incompatibility with the dominant top‑down design philosophy and the dominance of preemptive threads, which offered broader applicability despite higher overhead.
It then describes the resurgence of coroutines as a response to the inefficiency of preemptive scheduling for IO‑bound tasks, highlighting the advantages of user‑mode cooperative scheduling (yield/resume) for reducing context‑switch costs.
Limitations of coroutines are listed, such as lack of native multi‑core utilization, potential starvation, and security concerns when user‑controlled scheduling replaces OS‑managed preemption.
The article surveys language support: Python’s evolution from generator‑based yields to async/await (with a code example), C++20’s low‑level coroutine framework used by libraries like boost::coroutine, and Go’s native goroutine model built on the GMP (G‑M‑P) scheduler.
import asyncio
from pathlib import Path
import logging
from urllib.request import urlopen, Request
import os
from time import time
import aiohttp
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
CODEFLEX_IMAGES_URLS = [
'https://codeflex.co/wp-content/uploads/2021/01/pandas-dataframe-python-1024x512.png',
'https://codeflex.co/wp-content/uploads/2021/02/github-actions-deployment-to-eks-with-kustomize-1024x536.jpg',
'https://codeflex.co/wp-content/uploads/2021/02/boto3-s3-multipart-upload-1024x536.jpg',
'https://codeflex.co/wp-content/uploads/2018/02/kafka-cluster-architecture.jpg',
'https://codeflex.co/wp-content/uploads/2016/09/redis-cluster-topology.png'
]
async def download_image_async(session, dir, img_url):
download_path = dir / os.path.basename(img_url)
async with session.get(img_url) as response:
with download_path.open('wb') as f:
while True:
chunk = await response.content.read(512)
if not chunk:
break
f.write(chunk)
logger.info('Downloaded: ' + img_url)
async def main():
images_dir = Path('codeflex_images')
Path('codeflex_images').mkdir(parents=False, exist_ok=True)
async with aiohttp.ClientSession() as session:
tasks = [download_image_async(session, images_dir, img_url) for img_url in CODEFLEX_IMAGES_URLS]
await asyncio.gather(*tasks, return_exceptions=True)
if __name__ == '__main__':
start = time()
event_loop = asyncio.get_event_loop()
try:
event_loop.run_until_complete(main())
finally:
event_loop.close()
logger.info('Download time: %s seconds', time() - start)Finally, the article concludes that coroutines complement, rather than replace, threads by excelling at IO‑bound workloads, and encourages developers to adopt coroutine‑friendly designs where appropriate.
Refining Core Development Skills
Fei has over 10 years of development experience at Tencent and Sogou. Through this account, he shares his deep insights on performance.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.