Python coroutine

yield

Since we want to talk about coroutines, we have to mention the usage of yield first. There are two main usages of yield. yield r and n = yield r ,

A brief understanding of yield: yield means that return returns a value, and remembers the position of this return, the next iteration will start from this position.

def foo():
    print("starting...")
    while True:
        res = yield 4
        print("res:", res)


g = foo()
print(next(g))
print("-" * 20)
print(next(g))
starting...
4
--------------------
res: None
4

n = yield r 和 r = c.send(n)

def foo():
    print("starting...")
    while True:
        res = yield 4
        print("res:", res)


g = foo()
print(next(g))
print("-" * 20)
# print(next(g))
print(g.send(7))
starting...
4
--------------------
res: 7
4

It is not difficult to understand from the above example, next(g) and g.send(param) are actually relatively similar, but the latter one passes the parameters in the next step, or you can also think that next(g) is also The parameters are passed in, but None is passed.

So, this can also explain why next(g) can also be replaced with g.send(None).

If you have any questions, you can take a look at this blog: https://blog.csdn.net/mieleizhi0522/article/details/82142856/ , I believe that after reading this blog, you can look at the code in the following example. It's struggling.

Coroutine

The biggest advantage of coroutine is its extremely high execution efficiency. Because subroutine switching is not thread switching, it is controlled by the program itself . Therefore, there is no thread switching overhead. Compared with multithreading, the more threads, the more obvious the performance advantage of coroutines.

The second major advantage is that there is no need for a multi-threaded lock mechanism, because there is only one thread, and there is no conflict of writing variables at the same time. In the coroutine, the shared resources are controlled without locking, and only the state is judged, so the execution efficiency is much higher. The thread is much higher.

Generally speaking, when talking about coroutines, I like to use the following classic producer consumer example: execution result:

[PRODUCER] Producing 1...
[CONSUMER] Consuming 1...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 2...
[CONSUMER] Consuming 2...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 3...
[CONSUMER] Consuming 3...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 4...
[CONSUMER] Consuming 4...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 5...
[CONSUMER] Consuming 5...
[PRODUCER] Consumer return: 200 OK

Operation process:

Note that the consumerfunction is one generator, after consumerpassing producein one:

  1. First call the c.send(None)startup generator (the utility next(c) startup is also possible);

  2. Then, once something is produced, c.send(n)switch to consumerexecution by;

  3. consumerBy yieldgetting the message, processing it, and passing yieldthe result back;

  4. produceGet the consumerprocessed result and continue to produce the next message;

  5. produceIt was decided not to produce, and the whole process ended by c.close()shutting down consumer.

The entire process is lock-free, executed by one thread, produceand consumercooperated to complete the task, so it is called "coroutine", rather than thread preemptive multitasking.

Guess you like

Origin blog.csdn.net/TomorrowAndTuture/article/details/115266112