Click open link

 

Definition of a coroutine According to Wikipedia, a coroutine is a program component, similar to a subroutine, but more general and flexible, but not as widely used in practice. Zh.wikipedia.org/wiki/%E5%8D… It’s actually a little bit tricky to understand, so let’s just ignore it and see what coroutines actually do.

Threads are contained in processes and coroutines are contained in threads. A thread can have as many coroutines as it wants as long as there is enough memory, but only one coroutine can be running at any one time, and multiple coroutines share the computer resources allocated by that thread.

Coroutines are similar to threads in multithreading: they have their own stack, their own local variables, and their own instruction Pointers, but share information such as global variables with other coroutines. The main difference between threads and coroutines is that, in the case of multiple processors, multithreading conceptually involves running multiple threads at the same time, whereas coroutines switch coroutines through code and only one coroutine is running at any one time. And the running coroutine will only be suspended if it is explicitly asked to be.

Coroutines are also called microthreads, but this name adds a bit of a hindrance to understanding them. Coroutines are essentially in one thread, so no matter how many coroutines there are, they run in serial, meaning that there are no different coroutines running at the same time, belonging to the same thread. So it itself avoids all the synchronization problems that multithreaded programming can cause.

Coroutines behavior is A bit like A function call, it’s different from the function call is, for the function call, if A function calls B function, you must wait for B function after will go back in A program is running process, but for coroutines, if in coroutines A cut to coroutines in B, coroutines B can choose A point back to A execution flow, It also allows you to go back to A before you go back to B at some point, which is impossible in A function. Because the function can only go all the way.

What exactly is a coroutine? What’s the use? Coroutines can be thought of as multithreading in user mode. In a multithreaded model, the operating system will be according to certain scheduling algorithm constantly switching the current thread is running, because each thread has its own stack, so in the process of switching threads need to context switch, which can cause a lot of cost, if the system in a large number of threads, the system resources will be context switching a large amount of consumption, Performance deteriorates. Coroutines are designed to solve this problem (among other advantages) by running on the same thread without context switching. Unlike threads, coroutines can have multiple entry points that suspend and resume execution at specified locations (threads have only one entry point and return only once).

The role of coroutines is described in the producer-consumer model.

In a traditional multithreaded model, one producer thread and one consumer thread are typically created, as shown in the following code (pseudocode).

Queue q; Void ProduceThread() void ProduceThread() void ProduceThread() {I = 0; while(true) { if (! q.IsFull()) { q.push(i); ++i; }}} void ConsumeThread() // consumer thread {I = 0; while(true) { if (! q.IsEmpty()) { print q.get(0); // Print the first element q.op (0); }}} int main() {Thread t1 = new Thread(ProceThread); Thread t2 = new Thread(ConsumeThread); t1.start(); t2.start(); Sleep(100s); return 0; }Copy the code

Using coroutine, the code implementation is as follows (pseudocode) :

Queue q; Void ProduceFunc() void ProduceFunc() {I = 0; while(true) { if (! q.IsFull()) { q.push(i); ++i; } resume(ConsumeFunc); }} void ConsumeFunc() {I = 0; while(true) { if (! q.IsEmpty()) { print q.get(0); // Print the first element q.op (0); } yield; }} int main() {ProduceFunc(); return 0; }Copy the code

First of all, there’s no difference between the two pieces of code, right? Actually in a multithreaded mode, it is possible that made multiple producers, consumers to spend, which is likely to appear such circumstance, the queue q in the production of 1, 2, 3 elements, but consumption began to print 1, this is related to multi-threaded scheduling, which thread won the CPU resources can perform (in general, This scheduling of the operating system is as fair as possible, i.e., producers and consumers are equally likely to be executed. But the operating system does the scheduling. If you look at the implementation of coroutines, resume is used to resume the last function executed, and yield is used to yield CPU resources. In the above example, ProduceFunc will be executed first, and production 1 will be placed in queue Q, at which point ProduceFunc will resume ConsumeFunc and let it continue (since ConsumeFunc has not been executed, it will be executed from the first line of the function, which is the first entry), ConsumeFunc will then consume 1 in queue Q, yield the CPU, and ProduceFunc will continue to execute, and when ProduceFunc resumes, ConsumeFunc will continue to execute from the last yield (this is the second entry, That is, coroutines have multiple entry points. Coroutines are similar to multithreading, so they can be “user mode” multithreading, but there is no context switch, and the scheduling of coroutines is to be controlled by the developers themselves.

In the example above, the producer generates a message, and then the consumer consumes a message. Why not just use synchronously executed code? But what if the consumer also waits for asynchronous messages? For example, to get some data from DB? This example doesn’t really show what coroutines can do, and I’ll give more examples that show the benefits of coroutines.

Copyright notice: This article is the blogger’s original article, shall not be reproduced without the permission of the blogger.

Blog.csdn.net/houzhuoming…