single-threaded execution
Python's built-in modules provide two built-in modules: thread and threading. thread is the source module and threading is the extension module, which is encapsulated and improved on the basis of thread. So you only need to use the threading module to complete the concurrency test.
an actual example
Create and start a single thread
import threading def myTestFunc(): print("I am a function.") t = (target=myTestFunc) # Create a thread () # Starting a thread
Implementation results
C:\Python36\ D:/MyThreading/ I'm a threaded function Process finished with exit code 0
In fact, the results of single-threaded execution and the results of a separate execution of a function or a group of functions is the same, the difference only lies in the use of threads to execute the function, and threads are able to execute more than one at the same time, the function can not be executed at the same time.
multithreaded execution
The above describes how to use single-threaded, multi-threaded just need to create multiple threads through a loop, and loop to start the thread execution can be
an actual example
import threading from datetime import datetime def thread_func(): # Threaded functions print('I am a threaded function', ()) def many_thread(): threads = [] for _ in range(10): # Create 10 threads in a loop t = (target=thread_func) (t) for t in threads: # Start 10 threads in a loop () if __name__ == '__main__': many_thread()
Implementation results
C:\Python36\ D:/MyThreading/ I'm a threaded function 2019-06-23 16:54:58.205146 I'm a threaded function 2019-06-23 16:54:58.205146 I'm a threaded function 2019-06-23 16:54:58.206159 I'm a threaded function 2019-06-23 16:54:58.206159 I'm a threaded function 2019-06-23 16:54:58.206159 I'm a threaded function 2019-06-23 16:54:58.207139 I'm a threaded function 2019-06-23 16:54:58.207139 I'm a threaded function 2019-06-23 16:54:58.207139 I'm a threaded function 2019-06-23 16:54:58.208150 I'm a threaded function 2019-06-23 16:54:58.208150 Process finished with exit code 0
Through the loop to create 10 threads, and executed 10 times the thread function, but it should be noted that python's concurrency is not in the absolute sense of simultaneous processing, because the start of the thread is started through the loop, there is still a sequence, through the execution of the results of the time can be seen there is still a slight difference, but can be ignored. Of course, if there are too many threads, the difference will be enlarged. Let's start 500 threads and see the program execution time.
an actual example
import threading from datetime import datetime def thread_func(): # Threaded functions print('I am a threaded function', ()) def many_thread(): threads = [] for _ in range(500): # Create 500 threads in a loop t = (target=thread_func) (t) for t in threads: # Start 500 threads in a loop () if __name__ == '__main__': start = ().now() many_thread() duration = ().now() - start print(duration)
Implementation results
0:00:00.111657 Process finished with exit code 0
The 500 threads executed for a total of about 0.11 seconds
So how can we optimize for this problem? We can create 25 threads, each thread executes the thread function 20 times, so that when the next thread is started, the previous thread is already in the loop, which greatly reduces the concurrency time difference
make superior
import threading from datetime import datetime def thread_func(): # Threaded functions print('I am a threaded function', ()) def execute_func(): for _ in range(20): thread_func() def many_thread(): start = () threads = [] for _ in range(25): # Create 500 threads in a loop t = (target=execute_func) (t) for t in threads: # Start 500 threads in a loop () duration = () - start print(duration) if __name__ == '__main__': many_thread()
output result(looking only at program execution intervals)
0:00:00.014959 Process finished with exit code 0
The latter optimization took 0.014 seconds to execute 500 concurrences. This is several times faster than the 500 concurrencies before the optimization, and the difference is even more significant if the threaded function takes longer to execute, so it is recommended to use the latter for extensive concurrency testing, which is closer to simultaneous "concurrency"
Daemon Thread
Multi-threading there is an important concept is the daemon thread. Then before we need to know the difference between the main thread and sub-threads, before the creation of the thread is actually a sub-thread of the main () thread, that is, first start the main thread main (), and then the execution of the thread function sub-thread.
So what is a daemon thread? It means that when the main thread finishes executing, all the sub-threads are also closed (no matter whether the sub-threads finish executing or not). By default, there is no daemon thread when it is not set. After the main thread finishes executing, it will wait for all the sub-threads to finish executing before it closes to end the program.
But this will have a disadvantage, when the sub-thread dead loop or has been waiting, the program will not be closed, was infinite hanging, we change the above thread function into a cycle of 10 times, and sleep for 2 seconds, so the effect will be more obvious!
import threading from datetime import datetime import time def thread_func(): # Threaded functions (2) i = 0 while(i < 11): print(()) i += 1 def many_thread(): threads = [] for _ in range(10): # Create 500 threads in a loop t = (target=thread_func) (t) for t in threads: # Start 500 threads in a loop () if __name__ == '__main__': many_thread() print("thread end")
Implementation results
C:\Python36\ D:/MyThreading/ thread end 2019-06-23 19:08:00.468612 2019-06-23 19:08:00.468612 2019-06-23 19:08:00.468612 2019-06-23 19:08:00.468612 2019-06-23 19:08:00.468612 2019-06-23 19:08:00.468612 2019-06-23 19:08:00.468612 2019-06-23 19:08:00.468612 2019-06-23 19:08:00.468612 2019-06-23 19:08:00.468612 2019-06-23 19:08:00.468612 2019-06-23 19:08:00.469559 2019-06-23 19:08:00.469559 2019-06-23 19:08:00.469559 2019-06-23 19:08:00.469559 2019-06-23 19:08:00.469559 2019-06-23 19:08:00.469559 2019-06-23 19:08:00.470556 2019-06-23 19:08:00.470556 2019-06-23 19:08:00.470556 2019-06-23 19:08:00.470556 2019-06-23 19:08:00.470556 2019-06-23 19:08:00.470556 2019-06-23 19:08:00.470556 2019-06-23 19:08:00.470556 2019-06-23 19:08:00.470556 2019-06-23 19:08:00.470556 2019-06-23 19:08:00.470556 2019-06-23 19:08:00.470556 2019-06-23 19:08:00.470556 2019-06-23 19:08:00.470556 2019-06-23 19:08:00.470556 2019-06-23 19:08:00.471554 2019-06-23 19:08:00.471554 2019-06-23 19:08:00.471554 2019-06-23 19:08:00.471554 2019-06-23 19:08:00.471554 2019-06-23 19:08:00.471554 2019-06-23 19:08:00.471554 2019-06-23 19:08:00.471554 2019-06-23 19:08:00.471554 2019-06-23 19:08:00.471554 2019-06-23 19:08:00.471554 2019-06-23 19:08:00.471554 2019-06-23 19:08:00.472557 2019-06-23 19:08:00.472557 2019-06-23 19:08:00.472557 2019-06-23 19:08:00.472557 2019-06-23 19:08:00.472557 2019-06-23 19:08:00.472557 2019-06-23 19:08:00.472557 2019-06-23 19:08:00.472557 2019-06-23 19:08:00.472557 2019-06-23 19:08:00.472557 2019-06-23 19:08:00.472557 2019-06-23 19:08:00.472557 2019-06-23 19:08:00.472557 2019-06-23 19:08:00.472557 2019-06-23 19:08:00.472557 2019-06-23 19:08:00.473548 2019-06-23 19:08:00.473548 2019-06-23 19:08:00.473548 2019-06-23 19:08:00.473548 2019-06-23 19:08:00.473548 2019-06-23 19:08:00.473548 2019-06-23 19:08:00.473548 2019-06-23 19:08:00.473548 2019-06-23 19:08:00.473548 2019-06-23 19:08:00.473548 2019-06-23 19:08:00.473548 2019-06-23 19:08:00.473548 2019-06-23 19:08:00.473548 2019-06-23 19:08:00.474545 2019-06-23 19:08:00.474545 2019-06-23 19:08:00.474545 2019-06-23 19:08:00.474545 2019-06-23 19:08:00.474545 2019-06-23 19:08:00.474545 2019-06-23 19:08:00.474545 2019-06-23 19:08:00.475552 2019-06-23 19:08:00.475552 2019-06-23 19:08:00.475552 2019-06-23 19:08:00.475552 2019-06-23 19:08:00.475552 2019-06-23 19:08:00.475552 2019-06-23 19:08:00.475552 2019-06-23 19:08:00.475552 2019-06-23 19:08:00.475552 2019-06-23 19:08:00.476548 2019-06-23 19:08:00.476548 2019-06-23 19:08:00.476548 2019-06-23 19:08:00.476548 2019-06-23 19:08:00.476548 2019-06-23 19:08:00.476548 2019-06-23 19:08:00.476548 2019-06-23 19:08:00.476548 2019-06-23 19:08:00.476548 2019-06-23 19:08:00.476548 2019-06-23 19:08:00.477546 2019-06-23 19:08:00.477546 2019-06-23 19:08:00.477546 2019-06-23 19:08:00.477546 2019-06-23 19:08:00.477546 2019-06-23 19:08:00.477546 2019-06-23 19:08:00.477546 2019-06-23 19:08:00.477546 2019-06-23 19:08:00.477546 2019-06-23 19:08:00.477546 2019-06-23 19:08:00.477546 2019-06-23 19:08:00.477546 Process finished with exit code 0
Based on the above results, you can see that after the main thread prints "thread end", the child threads continue to execute and do not end with the main thread.
Here we add a daemon to the sub-thread through the setDaemon method, we change the loop to a dead loop, and then look at the output (note that the daemon should be added before start)
import threading from datetime import datetime def thread_func(): # Threaded functions i = 0 while(1): print(()) i += 1 def many_thread(): threads = [] for _ in range(10): # Create 500 threads in a loop t = (target=thread_func) (t) (True) # Add daemon threads to each child thread for t in threads: # Start 500 threads in a loop () if __name__ == '__main__': many_thread() print("thread end")
output result
2019-06-23 19:12:35.564539 2019-06-23 19:12:35.564539 2019-06-23 19:12:35.564539 2019-06-23 19:12:35.564539 2019-06-23 19:12:35.564539 2019-06-23 19:12:35.564539 2019-06-23 19:12:35.565529 2019-06-23 19:12:35.565529 2019-06-23 19:12:35.565529 thread end Process finished with exit code 0
Through the results we can find that the main thread is closed after the sub-thread will also be closed, and not an infinite loop continues, this is like the program execution to half of the forced closure of the execution, it seems violent but very useful, if the sub-thread to send a request did not receive the request results, it is not possible to wait forever, this time you need to force the closure. So the daemon thread solves the problem of closing the main thread and sub-threads.
Clogging threads
The role of the daemon thread is described above, so is there another way to solve the above problem? In fact, there is, that is, blocking threads, this way is more reasonable, the use of join () method blocking threads, so that the main thread to wait for the completion of the sub-thread execution and then down the execution, and then shut down all the sub-threads, rather than as long as the main thread is over, regardless of the completion of the execution of the sub-thread whether the sub-thread is terminated sub-thread execution. Here we add join() to the sub-threads (the main join should be added to the start after)
import threading from datetime import datetime import time def thread_func(): # Threaded functions (1) i = 0 while(i < 11): print(()) i += 1 def many_thread(): threads = [] for _ in range(10): # Create 500 threads in a loop t = (target=thread_func) (t) (True) # Add daemon threads to each child thread for t in threads: # Start 500 threads in a loop () for t in threads: () # Blocking threads if __name__ == '__main__': many_thread() print("thread end")
Implementation results
The program will keep on executing, but it will not print the "thread end" statement, because the child thread is not finished, so the main thread will keep on waiting.
Question: Some people may think that this is the same as not setting anything, but in fact there is a slight difference, as can be seen from the definitions of daemon and thread blocking, if nothing is set, then the main thread will finish executing first and print "thread end" after it while waiting for the child thread to finish executing. If both are set, then the main thread will wait for the child thread to finish before continuing.
For the dead loop or have been waiting for the case, we can set a timeout for join, we set the join parameter to 2, then the sub-thread will tell the main thread to let it wait 2 seconds, if the sub-thread within 2 seconds of the end of the execution of the main thread will continue to execute, if the sub-thread is not the end of the 2 seconds, the main thread will continue to execute the next execution is complete, the execution is complete to shut down the sub-thread
output result
import threading from datetime import datetime import time def thread_func(): # Threaded functions (1) i = 0 while(1): print(()) i += 1 def many_thread(): threads = [] for _ in range(10): # Create 500 threads in a loop t = (target=thread_func) (t) (True) # Add daemon threads to each child thread for t in threads: # Start 500 threads in a loop () for t in threads: (2) # Set the sub-thread timeout to 2 seconds if __name__ == '__main__': many_thread() print("thread end")
When you run the program, you'll notice that after about 2 seconds of running, the program will read "thread end" and end the execution of the program, which is the meaning of blocking threads, controlling the order of execution of the sub-threads and the main thread.
summarize
Better yet, once again, the definitions of daemon threads and blocking threads
- Guardian threads: child threads end with the main thread, regardless of whether the child thread has finished executing or not
- Blocking threads: the main thread waits for the execution of the child threads to finish before continuing execution
This is the whole content of this article.