Concurrent programming--coroutines

  Coroutines, also known as micro-threads, can be understood as switchable functions or generators. Coroutines are always executed in a single thread, so there is no resource conflict problem and no locking mechanism is required. The following is an example of Fibonacci numbers, plus some of my own understanding, to talk about this a little bit.

A common implementation of the Fibonacci sequence

A general function can only have one return value, return, and the program is no longer executed after the return. as follows:

#Ordinary implementation of Fibonacci sequence 
def fib(n):
    res = [0] * n
    index = 0
    a = 0
    b = 1
    while index < n:
        res[index] = b
        a, b = b, a+b   #Swap positions
        index += 1
    return res
# print(fib(5))
"""
fib is an ordinary function that can only be returned in return
"""

Fibonacci sequence yield implementation

Implement a generator object through yield to get the array. The yield generator is called every next or __next__(), and each time the calling program executes to yield, it returns and hangs; waiting for the next next call.

# Fibonacci's yield implementation 
def fib_1(n):
    index = 0
    a = 0
    b = 1
     while index < n:
         yield b   #Return b, every time it is executed, return once, hang the program, execute 
        a, b = b, a+ b every time __next__() is called
        index += 1

# f = fib_1(5)
# print(f.__next__())
# print(f.__next__())
# print(f.__next__())
# print(f.__next__())
# print(f.__next__())
"""
At this time, fib_1 is a generator object. Every time the program executes to yield b, it returns a b and suspends the program.
Wait for the next call to next,
The next time __next__() is called, the program continues from where it hangs (executes the code below)
Continue to execute to yield b, return to b at this time and hang the program, wait for the next call, until the loop condition is met, stop the iteration
After the conditions are met, the generator has no data to take, and if the call continues, the program will report an error
"""

 

Fibonacci number sequence

The generator can return a value during execution, and can also pass parameters to it during execution. The parameter keyword send Therefore, you can write two functions, one that returns a value, and one that sends a value to it.

def fib_2(n):
    index = 0
    a = 0
    b = 1
    while index < n:
        c = yield b   # hangs when calling next, the generator returns b and receives the passed parameters, and uses c to record the first come 
        print ( " -->send:{} " .format(c))
        time.sleep(c)
        a, b = b, a+b
        index += 1

# f = fib_2(10)
# print(next(f))

In c = yield b, there is no assignment relationship between b and c, the program has given the return value when yield b, and = cannot be understood as assignment. The equal sign "=" here is equivalent to a pipe, and one end of the pipe is used to return b (that is, processing yield b), the other end of the pipeline is used to receive the parameters passed by send, and use c to record the passed value, and provide it to the program for later use
only for personal understanding, not necessarily correct. . . . . .

Continue to add in the above code:

# while True:
#     f.send(random.randint(1, 3))

"""The 
program switches execution inside and outside the function, the
program first executes to yield b, fib_2 has returned, switch to outside the function,
no longer execute the internal code of fib_2, but execute the while True outside the function;
until the execution reaches send When , switch to the inside of the function, continue to execute the code inside the function,
until the yield inside the function is executed, then switch to the outside of the function to loop back and
forth...
"""

Implement a producer-consumer model using yield

#Use yield to implement a producer and consumer model 
import time
 def Consumer():
    r = ''
    while True:
        n = yield r
         if  not n:
             return 
        print ( ' Consuming <{}>... ' .format(n))
        time.sleep(1)
        r = '200'

def Producer(c):
    c.send(None) #Start   the generator, run the code to the yield line, and return (equivalent to the next call)
    n = 1
    while n < 6:
        print("生产<{}>中...".format(n))
        time.sleep(1)
        r = c.send(n) #Send   the value to the generator and give the execution right to the consumer 
        print ( " Consumed! status_code:{}\n " .format(r))
        n += 1
    c.close()

c = Consumer() #Get   a generator. Since the generator is not called, 
Producer(c) #function   call is not executed . When send is executed, the generator consumer is started (equivalent to the next call)

Results of the:

The specific code is as follows:

"""
Coroutines, also known as microthreads

Supplementary knowledge points
iterable (iterable object), an object that can be used in a for loop
itertor (iterator), an object that can be used for the next value
iterion (iteration)

""" 
#Ordinary implementation of Fibonacci sequence 
def fib(n):
    res = [0] * n
    index = 0
    a = 0
    b = 1
    while index < n:
        res[index] = b
        a, b = b, a+b   #Swap positions
        index += 1
    return res
# print(fib(5))
"""
fib is an ordinary function that can only be returned in return
"""

# Fibonacci's yield implementation 
def fib_1(n):
    index = 0
    a = 0
    b = 1
     while index < n:
         yield b   #Return b, every time it is executed, return once, hang the program, execute 
        a, b = b, a+ b every time __next__() is called
        index += 1

# f = fib_1(5)
# print(f.__next__())
# print(f.__next__())
# print(f.__next__())
# print(f.__next__())
# print(f.__next__())
"""
At this time, fib_1 is a generator object. Every time the program executes to yield b, it returns a b and suspends the program.
Wait for the next call to next,
The next time __next__() is called, the program continues from where it hangs (executes the code below)
Continue to execute to yield b, return to b at this time and hang the program, wait for the next call, until the loop condition is met, stop the iteration
After the conditions are met, the generator has no data to take, and if the call continues, the program will report an error
"""

#Fibonacci number sequence parameter 
"""
The generator can return a value during execution, and can also pass parameters to it during execution.
parameter keyword send
Therefore, you can write two functions, one that returns a value and one that sends a value to it
"""
import time

def fib_2(n):
    index = 0
    a = 0
    b = 1
    while index < n:
        c = yield b   # hangs when calling next, the generator returns b and receives the passed parameters, and uses c to record the first come 
        print ( " -->send:{} " .format(c))
        time.sleep(c)
        a, b = b, a+b
        index += 1

# f = fib_2(10)
# print(next(f))
"""
In c = yield b, there is no assignment relationship between b and c,
When yield b, the program has given the return value, and = cannot be understood as assignment
The equal sign "=" here is equivalent to a pipe,
One end of the pipe is used to return b (i.e. process yield b),
The other end of the pipeline is used to receive the parameters of send, and use c to record the passed value, and provide it to the program for later use.

Only personal understanding, not necessarily correct. . . . . .
"""


# while True:
#     f.send(random.randint(1, 3))
"""
The program switches execution between inside and outside the function,
The program is first executed to yield b, fib_2 has returned, switch to the outside of the function,
The code inside fib_2 is no longer executed, but the while True outside the function;
Until the execution reaches send, switch to the inside of the function and continue to execute the code inside the function,
Until the yield inside the function is executed, it switches to the outside of the function
cycle back and forth. . . . .
"""

#Coroutine understanding: functions that can be switched, or generators 
#Coroutines are always executed in a single thread, so there is no resource conflict problem and no locking mechanism is required

#Use yield to implement a producer and consumer model 
import time
 def Consumer():
    r = ''
    while True:
        n = yield r
         if  not n:
             return 
        print ( ' Consuming <{}>... ' .format(n))
        time.sleep(1)
        r = '200'

def Producer(c):
    c.send(None) #Start   the generator, run the code to the yield line, and return (equivalent to the next call)
    n = 1
    while n < 6:
        print("生产<{}>中...".format(n))
        time.sleep(1)
        r = c.send(n) #Send   the value to the generator and give the execution right to the consumer 
        print ( " Consumed! status_code:{}\n " .format(r))
        n += 1
    c.close()

c = Consumer() #Get   a generator. Since the generator is not called, 
Producer(c) #function   call is not executed . When send is executed, the generator consumer is started (equivalent to the next call)

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325874366&siteId=291194637