In 2004, Ana Lucia de Moura and Roberto Ierusalimschy, the authors of Lua, published the paper "Revisiting Coroutines", proposing to classify coroutines according to three factors:
Control-transfer mechanism
Stackful structure
First-class objects in programming languages
Coroutine based on control transfer
Control Transfer Mechanism: Symmetric v.s. Asymmetric Coroutines
Symmetric coroutines:
Provides only one transfer operation for directly transfer control between coroutines
The symmetric coroutines are all equivalent, and the control is directly transferred between the symmetric coroutines
When the symmetric coroutine is suspended, it actively specifies another symmetric coroutine to receive control
use futures::executor::block_on;
asyncfnhello_world() {
println!("hello, world!");
}
fnmain() {
let future = hello_world(); // Nothing is printed
block_on(future); // `future` is run and "hello, world!" is printed
}
import requests
from timer import timer
URL = 'https://httpbin.org/uuid'deffetch(session, url):with session.get(url) as response:
print(response. json()['uuid'])
@timer(1, 1)defmain():with requests.Session() as session:
for _ inrange(100):
fetch(session, URL)
Process/thread/coroutine performance comparison
Multi-process: 7 seconds
from multiprocessing.pool import Pool
import requests
from timer import timer
URL = 'https://httpbin.org/uuid'deffetch(session, url):with session.get(url) as response:
print(response. json()['uuid'])
@timer(1, 1)defmain():with Pool() as pool:
with requests.Session() as session:
pool.starmap(fetch, [(session, URL) for _ inrange(100)])
Process/thread/coroutine performance comparison
Thread: 4 seconds
from concurrent.futures import ThreadPoolExecutor
import requests
from timer import timer
URL = 'https://httpbin.org/uuid'deffetch(session, url):with session.get(url) as response:
print(response. json()['uuid'])
@timer(1, 1)defmain():with ThreadPoolExecutor(max_workers=100) as executor:
with requests.Session() as session:
executor. map(fetch, [session] * 100, [URL] * 100)
executor. shutdown(wait=True)
fnmain() {
let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); // bind listenerlet pool = ThreadPool::new(100); // same number as max concurrent requestsletmut count = 0; // count used to introduce delays// listen to all incoming request streamsfor stream in listener.incoming() {
let stream = stream. unwrap();
count = count + 1;
pool. execute(move || {
handle_connection(stream, count); // spawning each connection in a new thread
});
}
}
What is a coroutine? https://zhuanlan.zhihu.com/p/172471249
Detailed explanation of coroutines in concurrent programming -- starting with python coroutines (3) https://blog.csdn.net/u013597671/article/details/89762233
The concept of a coroutine was first proposed and implemented by Melvin Conway in 1963 to simplify the cooperation between the lexical and syntactic analyzers of the COBOL compiler. At that time, his description of the coroutine was "similar to the main program subroutine".
Detailed explanation of coroutines in concurrent programming -- starting with python coroutines (3) https://blog.csdn.net/u013597671/article/details/89762233
Learning thinking about Generator/async/await in Coroutine-ES https://blog.csdn.net/shenlei19911210/article/details/61194617
C++20 coroutine principle and application https://zhuanlan.zhihu.com/p/498253158
Detailed explanation of coroutines in concurrent programming -- starting with python coroutines (3) https://blog.csdn.net/u013597671/article/details/89762233
The coroutines provided to support concurrency are usually symmetric coroutines, which are used to represent independent execution units, such as coroutines in golang. Coroutines that produce sequences of values are asymmetric coroutines, such as iterators and generators.
These two control transfer mechanisms can express each other, so only one of them needs to be implemented to provide a common coroutine. However, the same expressive power does not mean that the two are also the same in ease of use. Symmetric coroutines make the control flow of the program relatively complex and difficult to understand and manage, while asymmetric coroutines behave like functions in a sense because control is always returned to the caller. Programs written using asymmetric coroutines are more structured.
Stacked coroutines and stackless coroutines https://cloud.tencent.com/developer/article/1888257

https://zhuanlan.zhihu.com/p/25513336
Coroutine from entry to persuasion
In addition, the wiki also classifies coroutines:
Asymmetric coroutine, asymmetric coroutine.
Symmetric coroutine, symmetric coroutine.
Semi-coroutine, semi-coroutine.
Stacked coroutines and stackless coroutines https://cloud.tencent.com/developer/article/1888257
Ref: https://os.phil-opp.com/async-await/#example
#### Concept of Future
* Three phases in asynchronous task:
1. **Executor**: A Future is **polled** which result in the task progressing
-Until a point where it can no longer make progress
2. **Reactor**: Register an **event source** that a Future is waiting for
- Makes sure that it will wake the Future when event is ready
3. **Waker**: The event happens and the Future is **woken up**
- Wake up to the executor which polled the Future
- Schedule the future to be polled again and make further progress
---
Asynchronous execution process based on polling Future
- The executor polls the `Future` until eventually the `Future` needs to perform some kind of I/O
- The `Future` will be handed off to the reactor that handles the I/O, i.e. the `Future` will wait for that specific I/O
- When an I/O event occurs, the reactor will use the passed `Waker` parameter to wake up the `Future` and pass it back to the executor
- Loop the above three steps until the final `future` task is completed (resolved)
- When the task is completed and the result is obtained, the executor releases the handle and the entire `Future`, and the entire calling process is completed
https://wiki.brewlin.com/wiki/compiler/rust%E5%8D%8F%E7%A8%8B_%E8%B0%83%E5%BA%A6%E5%99%A8%E5%AE% 9E%E7%8E%B0/
The core of understanding coroutines is to suspend and resume. Rust's coroutines do this through a state machine, and golang does this through an independent stack. It is important to understand this
Java coroutines are coming https://cloud.tencent.com/developer/article/1949981
In-depth Lua: The implementation of coroutines https://zhuanlan.zhihu.com/p/99608423
Coroutines in Rust: Future and async/await https://zijiaw.github.io/posts/a7-rsfuture/
Go by Example Chinese Version: Coroutines
https://gobyexample-cn.github.io/goroutines
Making multiple HTTP requests using Python (synchronous, multiprocessing, multithreading, asyncio)
https://www.youtube.com/watch?v=R4Oz8JUuM4s
https://github.com/nikhilkumarsingh/async-http-requests-tut
asyncio is a standard library introduced by Python 3.4, which directly has built-in support for asynchronous IO. Just add the async keyword in front of a function to turn a function into a coroutine.
Process, Thread and Coroutine (Process, Thread and Coroutine) theory, practice, code python
https://leovan.me/cn/2021/04/process-thread-and-coroutine-theory/
https://leovan.me/cn/2021/04/process-thread-and-coroutine-python-implementation/
https://github.com/leovan/leovan.me/tree/master/scripts/cn/2021-04-03-process-thread-and-coroutine-python-implementation