The duration of this section needs to be controlled 15 Within minutes
The topic of this section is to realize concurrency based on single thread , Only one main thread ( Obviously available cpu only one ) To achieve concurrency , So we need to review the nature of concurrency : Switch + Save state
cpu Running a task , Will cut off in two cases to perform other tasks ( Switching is forced by the operating system ), One situation is that the task is blocked , Another situation is that the task takes too long to calculate or a higher priority program replaces it
ps: In introducing process theory , Mention three execution states of a process , The thread is the execution unit , So we can also understand the above figure as three states of thread
One : The second case doesn't improve efficiency , Just to make cpu Be able to touch the rain and dew , Implementation looks like all tasks are “ meanwhile ” The effect of execution , If multiple tasks are purely computational , This kind of switching will reduce the efficiency . For this we can base on yield To verify .yield It is a way to save the running state of a task in a single thread , Let's review briefly :
1 yiled Can save state ,yield The state saving of is similar to the thread state saving of the operating system , however yield It's code level control , More lightweight
2 send You can pass the result of one function to another , In this way, the switch between programs in a single thread can be realized
Simply switching will reduce the operation efficiency
# Serial execution
import time
def consumer(res):
''' Mission 1: receive data , Processing data '''
pass
def producer():
''' Mission 2: The production data '''
res=[]
for i in range(10000000):
res.append(i)
return res
start=time.time()
# Serial execution
res=producer()
consumer(res) # It's written in consumer(producer()) Will reduce the efficiency of execution
stop=time.time()
print(stop-start) #1.5536692142486572
# be based on yield Concurrent execution
import time
def consumer():
''' Mission 1: receive data , Processing data '''
while True:
x=yield
def producer():
''' Mission 2: The production data '''
g=consumer()
next(g)
for i in range(10000000):
g.send(i)
start=time.time()
# be based on yield Save state , Two tasks can be switched back and forth directly , That is, the effect of concurrency
#PS: If printing is added to every task , So it's obvious that the printing of the two tasks is once for you and once for me , That is, concurrent execution .
producer()
stop=time.time()
print(stop-start) #2.0272178649902344
Two : Switching in the first case . At the moment of the mission io Under the circumstances , Cut to task two to execute , In this way, we can use the blocking time of task one to complete the calculation of task two , The improvement of efficiency lies in this .
yield It doesn't work io Switch
import time
def consumer():
''' Mission 1: receive data , Processing data '''
while True:
x=yield
def producer():
''' Mission 2: The production data '''
g=consumer()
next(g)
for i in range(10000000):
g.send(i)
time.sleep(2)
start=time.time()
producer() # Concurrent execution , But the task producer encounter io It's going to block , It doesn't switch to other tasks in the thread to execute
stop=time.time()
print(stop-start)
For single thread , We cannot avoid the emergence of io operation , But if we can in our own program ( That is, the user program level , Not at the operating system level ) Controlling multiple tasks under a single thread can be encountered in one task io When blocked, switch to another task to calculate , This ensures that the thread is in the ready state to the maximum extent , That is, it can be cpu Status of execution , It's equivalent to us putting our own io Operations are hidden to the maximum extent , So you can confuse the operating system , Let it see : The thread seems to have been calculating ,io less , So more will be cpu The execution permission of is assigned to our thread .
The essence of a process is to run on a single thread , User controls a task encounter io If it's blocked, switch to another task to execute , To improve efficiency . In order to achieve it , We need to find a solution that can meet the following conditions at the same time :
1\. You can control the switching between multiple tasks , Save the state of the task before switching , In order to re run , You can continue execution based on where you pause .
2\. As 1 A supplement to : It can detect io operation , In case of io Switching occurs in the case of operation
coroutines : It's concurrency under single thread , Also called tasklet , fibers . English name Coroutine. In a word, what is thread : Coroutine is a lightweight thread in user mode , That is, the scheduling is controlled by the user program itself .、
It's important to note that :
1\. python The threads of are kernel level , That is, scheduling is controlled by the operating system ( If a single thread encounters io Or if the execution time is too long, it will be forced to hand over cpu Executive authority , Switch other threads to run )
2\. Start the process in a single thread , Once encountered io, From the application level ( Not the operating system ) Control switch , To improve efficiency (!!! Not io The switching of operation has nothing to do with efficiency )
Compare the switching of operating system control threads , The user controls the switch of the process in a single thread
Advantages as follows :
1\. The switching cost of the cooperation process is less , Switching at the program level , The operating system is completely unaware of , So it's more lightweight
2\. Single thread can achieve the effect of concurrency , Make the most of cpu
Drawbacks as follows :
1\. The essence of the process is single thread , Can't use multi-core , Can be a program to open multiple processes , Open multiple threads in each process , Start the process in each thread
2\. A process is a single thread , So once the process is blocked , Will block the entire thread
Summarize the characteristics of the process :