Python thread mutex lock-Python zero-based introductory tutorial

Python thread mutex lock-Python zero-based introductory tutorial

table of Contents

I. Introduction

In the previous article, Python thread creation and parameter transfer , we introduced some simple function usage and thread parameter transfer about Python threads. Using multiple threads can perform multiple tasks at the same time and improve development efficiency. However, in actual development, we often You will encounter thread synchronization problems. If there is such a scenario: accumulate global variables 1,000,000 times, in order to improve efficiency, we can use multi-threaded completion, the sample code is as follows:

# !usr/bin/env python # -*- coding:utf-8 _*- """ @Author: Ape said programming @Blog (personal blog address): www.codersrc.com @File: Python thread mutex Lock.py @Time:2021/04/22 08:00 @Motto: If you don't accumulate steps, you can't reach a thousand miles. If you don't accumulate small streams, you can't make a sea. The splendor of the program life needs to be accumulated! """ # Import threading module import threading # Declare global variables g_num = 0 def my_thread1(): # Declare global variables global g_num # Cycle 1000000 times, add 1 each time for i in range(0,1000000): g_num = g_num + 1 def my_thread2(): # Declare global variables global g_num # Cycle 1000000 times, add 1 each time for i in range(0,1000000): g_num = g_num + 1 def main(i): # Declare global variables global g_num # Initialize global variables, the initial value is 0 g_num = 0 # Create two threads and add 1 to the global variables cumulatively t1 = threading.Thread(target=my_thread1) t2 = threading.Thread(target=my_thread2) # Start thread t1.start() t2.start() # Blocking function, waiting for the end of the thread t1.join() t2.join() # Get the value of the global variable print("%d calculation result: %d "% (i,g_num)) if __name__ == "__main__": # Loop 4 times, call the main function, calculate the value of the global variable for i in range(1,5): main(i) ''' Output result: The first calculation result: 1262996 The second calculation result: 1661455 The third calculation result: 1300211 The fourth calculation result: 1563699 ''' Copy code

what? What is this operation? ? Looking at the code, it seems that there is no problem. Two threads, each accumulating 1,000,000 times, shouldn't the output be 2,000,000 times? And the main function is called 4 times , and the output result is different each time! !

2. Python threads share global variables

Analyze the above code: two threads share global variables and execute a for loop 1000000, automatically incrementing by 1 each time, we all know that both threads are running at the same time, that is to say, two threads are executing at the same time g_num = g_num + 1 Operation, after our calm analysis, it seems that the result should be equal to 2,000,000, right?

1. we divide the code for automatically adding 1 to the global variable above into two steps:

The first step: g_num + 1 Step 2: Assign the result of g_num + 1 to g_num Copy code

It can be seen that two steps are required to perform a complete automatic increment process, but the threads are running at the same time. No one can guarantee that the first and second steps of thread 1 will be executed before the first and second steps of thread 2 are executed. In the second step, the execution process is full of randomness, which is why the calculation results are different each time!

Give a simple example:

If the current g_num value is 100, when thread 1 executes the first step, the cpu obtains the result 101 through calculation, and is ready to assign the calculated result 101 to g_num, and then in the process of passing the value, thread 2 suddenly starts to execute and execute After the first step, the value of g_num is still not 100, 101 is still in the process of being passed, and the value has not been successfully assigned. Thread 2 obtains the calculation result 101 and prepares to pass it to g_num. After going back and forth, it is clear After adding 1 twice, the result of g_num is 101, and the error is caused by this. The more the number of loops is, the larger the error is.

Three. Python thread mutex lock

In order to avoid the above problems, we can use thread mutex locks to solve this problem. So what is the principle of a mutex? Mutex locks are like queuing to go to the toilet. Only one person can squat in a pit. Only the person occupying the pit can go to the toilet!

1. Create a mutex

Import the threading module and create a mutex lock through threading.Lock .

# Import threading module import threading # Create a mutex mutex = threading.Lock() Copy code

2. Lock resources/unlock resources

  • **acquire ** The resource is locked. At this time, the resource is locked, and other threads cannot modify the locked resource until the locked resource is released .
  • Release - release of resources, also known as the unlocking operation of the lock to unlock resources, after unlocking other threads can operate normally for resources ;

Take the above code as an example: If you want to get the correct result, you can directly use the mutex lock to lock the resource before the global variable is increased by 1, and then release the resource after the calculation is completed. This is a complete calculation process. As for which thread should execute first , It doesn't matter, first come first served, speak according to ability ... The demo code is as follows:

# !usr/bin/env python # -*- coding:utf-8 _*- """ @Author: Ape said programming @Blog (personal blog address): www.codersrc.com @File: Python thread mutex Lock.py @Time:2021/04/22 08:00 @Motto: If you don't accumulate steps, you can't reach a thousand miles. If you don't accumulate small streams, you can't make a sea. The splendor of the program life needs to be accumulated! """ # Import threading module import threading # Declare global variables g_num = 0 # Create a mutex mutex = threading.Lock() def my_thread1(): # Declare global variables global g_num # Cycle 1000000 times, add 1 each time for i in range(0,1000000): # Lock resources mutex.acquire() g_num = g_num + 1 # Unlock resources mutex.release() def my_thread2(): # Declare global variables global g_num # Cycle 1000000 times, add 1 each time for i in range(0,1000000): # Lock resources mutex.acquire() g_num = g_num + 1 # Unlock resources mutex.release() def main(i): # Declare global variables global g_num # Initialize global variables, the initial value is 0 g_num = 0 # Create two threads and add 1 to the global variables cumulatively t1 = threading.Thread(target=my_thread1) t2 = threading.Thread(target=my_thread2) # Start thread t1.start() t2.start() # Blocking function, waiting for the end of the thread t1.join() t2.join() # Get the value of the global variable print("%d calculation result: %d "% (i,g_num)) if __name__ == "__main__": # Loop 4 times, call the main function, calculate the value of the global variable for i in range(1,5): main(i) ''' Output result: The first calculation result: 2000000 The second calculation result: 2000000 The third calculation result: 2000000 The fourth calculation result: 2000000 ''' Copy code

It can be seen that after the global variable calculation plus the mutex lock, the calculation result is the same no matter how many times it is executed. Note: Once the mutex is locked, remember to unlock it, otherwise the resource will remain locked;

Four. Python thread deadlock

1. The deadlock of a single mutex: acquire/release appear in pairs. After the mutex locks the resource, it must be unlocked, otherwise the resource will remain locked and other threads cannot modify it ; just like the code above, If any thread does not release the resource release , the program will always be blocked (waiting for the resource to be released). If you don t believe it, you can give it a try~

2. Deadlock of multiple mutexes: Be careful when operating multiple mutexes at the same time, because if you are not careful, it is easy to enter an infinite loop . If there is such a scenario: Boss allows programmers to implement functions. The development of, let the programmer two realize the development of function two, and integrate the code together after the function development is completed!

# !usr/bin/env python # -*- coding:utf-8 _*- """ @Author: Ape said programming @Blog (personal blog address): www.codersrc.com @File: Python thread mutex Lock.py @Time:2021/04/22 08:00 @Motto: If you don't accumulate steps, you can't reach a thousand miles. If you don't accumulate small streams, you can't make a sea. The splendor of the program life needs to be accumulated! """ # Import threading module import threading # Import thread time module import time # Create a mutex mutex_one = threading.Lock() mutex_two = threading.Lock() def programmer_thread1(): mutex_one.acquire() print("I am a programmer 1, and the development of module1 has officially started, no one should touch my code") time.sleep(2) # It will be blocked at this time, because this mutex_two has been locked by the thread programmer_thread2 first, waiting to be unlocked mutex_two.acquire() print("Waiting for programmer 2 to notify me of the merge code") mutex_two.release() mutex_one.release() def programmer_thread2(): mutex_two.acquire() print("I am a programmer 2, and the development of module2 has officially started, no one should touch my code") time.sleep(2) # It will be blocked at this time, because this mutex_one has been locked by the thread programmer_thread1 first, waiting to be unlocked mutex_one.acquire() print("Waiting for programmer 1 to notify me of the merge code") mutex_one.release() mutex_two.release() def main(): t1 = threading.Thread(target=programmer_thread1) t2 = threading.Thread(target=programmer_thread2) # Start thread t1.start() t2.start() # Blocking function, waiting for the end of the thread t1.join() t2.join() # End of integration code print("End of integration code") if __name__ == "__main__": main() ''' Output result: I am programmer 1, and the development of module1 has officially started, no one should touch my code I am a programmer 2, and the development of module2 has officially started, no one should touch my code ''' Copy code

Analyze the above code: Programmer 1 is waiting for the notification from Programmer 2, and Programmer 2 is waiting for the notification from Programmer 1. Both threads are blocked because both threads are waiting for the other to unlock. This is a deadlock! Therefore, we still need to pay more attention to the problem of deadlock in development!

V. Key summary

  • 1. To share global variables between threads, a mutex lock needs to be set;
  • 2. Note that **acquire/release ** appear in pairs in the mutex operation to avoid deadlock;

6. Guess you like it

  1. Python for loop
  2. Python string
  3. Python list list
  4. Python tuple
  5. Python dictionary dict
  6. Python conditional deduction
  7. Python list comprehensions
  8. Python dictionary comprehension
  9. Python function declaration and call
  10. Python variable length parameter *argc/**kargcs
  11. Python anonymous function lambda
  12. Python return logic judgment expression
  13. Python string/list/tuple/dictionary conversion
  14. Python local variables and global variables
  15. Difference between Python type function and isinstance function
  16. Difference between Python is and ==
  17. Python variable data types and immutable data types
  18. Python shallow copy and deep copy

Do not reprint without permission: Yuan Shuo Programming Python Thread Mutex Lock

This article from the blog - ape said programming ape said the software release!