(Update time) March 28, 2021 python basics (use of threads)

(Update time) March 28, 2021 python basics (use of threads)

1. The use of threads

1. Import the thread module

#Import threading module import threadingCopy code

2. Thread parameter description

Thread([group [, target [, name [, args [, kwargs]]]]])

  • group: Thread group, currently only None can be used
  • target: the name of the target task to be executed
  • args: pass parameters to the execution task in the form of tuples
  • kwargs: pass parameters to the execution task in a dictionary
  • name: thread name, generally do not need to be set

3. Start the thread

Start the thread using the start method

4. Multi-threaded code for multi-tasking

import threading import time # Singing task def sing (): # Extension: Get the current thread # print("The currently executing thread of sing is:", threading.current_thread()) for i in range ( 3 ): print ( "Singing...% d" % i) time.sleep( 1 ) # Dancing task def dance (): # Extension: Get the current thread # print("The thread currently executed by dance is:", threading.current_thread()) for i in range ( 3 ): print ( "Dancing...% d" % i) time.sleep( 1 ) if __name__ == ' __main__ ' : # Extension: Get the current thread # print("The currently executing thread is:", threading.current_thread()) # Create a singing thread # target: The name of the function executed by the thread sing_thread = threading.Thread(target=sing) # Create a dancing thread dance_thread = threading.Thread(target=dance) # Start thread sing_thread.start() dance_thread.start() Copy code

5. Summary

  • Import thread module
import threadingcopy code
  • Create child threads and specify tasks to be performed
sub_thread = threading.Thread (target = task name) Copy the code
  • Start threads to perform tasks
sub_thread.start() Copy code

2. Thread executes tasks with parameters

1. Introduction to thread execution of tasks with parameters

Previously, the tasks we performed using threads had no parameters. If the tasks we performed using threads had parameters, how to pass parameters to functions?

There are two ways for the Thread class to perform tasks and pass parameters to tasks:

  • args means to pass parameters to the execution task in the form of tuples
  • kwargs means to pass parameters to the execution task in a dictionary

2. The use of args parameters

Sample code:

import threading import time # Task with parameters def task ( count ): for i in range (count): print ( "Task is executing.." ) time.sleep( 0.2 ) else : print ( "Task execution completed" ) if __name__ == ' __main__ ' : # Create subthread # args: Pass parameters to the task in the form of tuples sub_thread = threading.Thread(target=task, args=( 5 ,)) sub_thread.start() Copy code

3. Use of kwargs parameters

Sample code:

mport threading import time # Task with parameters def task ( count ): for i in range (count): print ( "Task is executing.." ) time.sleep( 0.2 ) else : print ( "Task execution completed" ) if __name__ == ' __main__ ' : # Create subthread # kwargs: means that the parameters are passed in a dictionary sub_thread = threading.Thread(target=task, kwargs={ "count" : 3 }) sub_thread.start() Copy code

4. Summary

There are two ways for threads to perform tasks and pass parameters:

  • Passing parameters in tuple mode (args): Passing parameters in tuple mode must be consistent with the order of the parameters.
  • Passing parameters in dictionary mode (kwargs): The key in the dictionary passing parameters in dictionary mode must be consistent with the parameter name.

Four. Points to note about the use of threads

1. Introduction to threads

  • Execution between threads is unordered
  • The main thread will wait for all the child threads to finish and then finish
  • Sharing global variables between threads
  • Errors in sharing global variable data between threads

2. The execution between threads is out of order

import threading import time def task (): time.sleep( 1 ) print ( "current thread:" , threading.current_thread().name) if __name__ == ' __main__ ' : for _ in range ( 5 ): sub_thread = threading.Thread(target=task) sub_thread.start() Copy code

Description:

  • The execution between threads is disordered, which is determined by the cpu scheduling. Which thread is scheduled by the cpu will be executed first, and threads that are not scheduled cannot be executed.
  • The execution between processes is also disordered, and it is determined by the operating system scheduling. Which process is scheduled by the operating system will be executed first, and processes without scheduling cannot be executed.

3. The main thread will wait for all the child threads to finish and then finish

If we create a child thread now, it takes about 2.5 seconds to execute the child thread. Now let the main thread execute for 1 second and exit the program. Check the execution result. The sample code is as follows:

import threading import time # Test whether the main thread will wait for the execution of the child thread to complete before exiting the program def show_info (): for i in range ( 5 ): print ( "test:" , i) time.sleep( 0.5 ) if __name__ == ' __main__ ' : sub_thread = threading.Thread(target=show_info) sub_thread.start() The main thread # 1 second delay the time.sleep ( . 1 ) Print ( "over" ) copy the code

Sample code for setting up the main thread of the daemon:

import threading import time # Test whether the main thread will wait for the execution of the child thread to complete before exiting the program def show_info (): for i in range ( 5 ): print ( "test:" , i) time.sleep( 0.5 ) if __name__ == ' __main__ ' : # Create a child thread to guard the main thread # daemon=True Thread # Guard the main thread mode 1 sub_thread = threading.Thread(target=show_info, daemon= True ) # Set to be the guardian main thread, the main After the thread exits, the child thread directly destroys the code that no longer executes the child thread # Guarding the main thread mode 2 # sub_thread.setDaemon(True) sub_thread.start() The main thread # 1 second delay the time.sleep ( . 1 ) Print ( "over" ) copy the code

3. Sharing global variables between threads

demand:

  • Define a list type global variable
  • Create two child threads to perform the task of adding data to global variables and the task of reading data from global variables

Check whether global variable data is shared between threads

import threading import time # Define global variables my_list = list () # Write data task def write_data (): for i in range ( 5 ): my_list.append(i) time.sleep( 0.1 ) print ( "write_data:" , my_list) # Read data task def read_data (): print ( "read_data:" , my_list) if __name__ == ' __main__ ' : # Create a thread to write data write_thread = threading.Thread(target=write_data) # Create a thread to read data read_thread = threading.Thread(target=read_data) write_thread.start() # Delay # time.sleep(1) # The main thread waits for the completion of the write thread and the code continues to execute write_thread.join() print ( "Start reading data" ) read_thread.start() Copy code

4. Errors in sharing global variable data between threads

demand:

  • Define two functions, realize the loop 1 million times, add 1 to the global variable every loop
  • Create two sub-threads to execute the corresponding two functions, and view the calculated results
import threading # Define global variable g_num = 0 # Loop once to add 1 to the global variable def sum_num1 (): for i in range ( 1000000 ): global g_num g_num += 1 print ( "sum1:" , g_num) # Loop once to add 1 to the global variable def sum_num2 (): for i in range ( 1000000 ): global g_num g_num += 1 print ( "sum2:" , g_num) if __name__ == ' __main__ ' : # Create two threads first_thread = threading.Thread(target=sum_num1) second_thread = threading.Thread(target=sum_num2) # Start thread first_thread.start() # Start thread second_thread.start() Copy code

be careful:

Multi-threaded errors occurred while operating data on global variables

Error analysis:

Both threads, first_thread and second_thread, must add 1 to the global variable g_num (the default is 0), but due to simultaneous operations of multiple threads, the following situations may occur:

  • When g_num=0, first_thread obtains g_num=0. At this time, the system schedules first_thread to "sleeping" state, and converts second_thread to "running" state, and t2 also obtains g_num=0
  • Then second_thread adds 1 to the obtained value and assigns it to g_num, so that g_num=1
  • Then the system schedules second_thread to "sleeping" and first_thread to "running". Thread t1 adds 1 to the 0 it got before and assigns it to g_num.
  • As a result, although both first_thread and first_thread add 1 to g_num, the result is still g_num=1

Solutions for global variable data errors:

Thread synchronization: to ensure that only one thread can operate global variables at the same time. Synchronization: it is coordinated synchronization and runs in a predetermined sequence. Such as: after you finish, let me talk about it, like a walkie-talkie in real life

The way of thread synchronization:

  1. Thread waiting (join)
  2. Mutex

Sample code for thread waiting:

import threading # Define global variable g_num = 0 # Loop 1000000 times and add 1 to the global variable each time def sum_num1 (): for i in range ( 1000000 ): global g_num g_num += 1 print ( "sum1:" , g_num) # Loop 1000000 times and add 1 to the global variable each time def sum_num2 (): for i in range ( 1000000 ): global g_num g_num += 1 print ( "sum2:" , g_num) if __name__ == ' __main__ ' : # Create two threads first_thread = threading.Thread(target=sum_num1) second_thread = threading.Thread(target=sum_num2) # Start thread first_thread.start() # The main thread waits for the execution of the first thread to complete the code and then continues to execute, let it execute the second thread # Thread synchronization: after a task is completed, another task can be executed, and only one task is executing at the same time first_thread.join() # Start thread second_thread.start() Copy code

5. Summary

  • Thread execution is out of order
  • By default, the main thread will wait for the execution of all sub-threads to finish before ending. The purpose of setting the guardian main thread is that the main thread exits and the sub-threads are destroyed.
  • Sharing global variables between threads has the advantage that the data of global variables can be shared.
  • Sharing global variables between threads may cause data errors. You can use thread synchronization to solve this problem.