Today's article , Let's talk about another indispensable part of the multithreading scenario —— lock .
If you have learned operating system , Then it should be no stranger to locks . The meaning of lock is thread lock , It can be used to specify that only one thread can access a certain logic or resource at the same time . It's easy to understand , It's like a room is locked by a lock , Only those who get the key can enter . Everyone gets the key from the door of the room and enters the room , When I leave the room, I will put the key back to the door . So the next person to the door can get the key . The room here is a resource or a piece of logic , The person who takes the key actually refers to a thread .
The reason for locking
We understand the principle of lock , I can't help but have a problem , Why do we need locks , In which scenes will it be used ?
In fact, it is widely used , Let's take a very simple example , Shopping on Taobao . We all know that the inventory of merchants is limited , Sell one less . Let's say there is only one commodity left in the current inventory , But now there are two people who buy at the same time . Two people buy at the same time, that is, there are two requests to initiate a purchase request at the same time , If we don't lock it , The inventory of goods queried by two threads at the same time is 1, Greater than 0, After the purchase logic , Minus one at the same time . Because two threads execute at the same time , So in the end, the inventory of goods will become -1.
Obviously, the inventory of goods should not be a negative number , So we need to avoid this happening . Locking can solve this problem perfectly . We stipulate that only one thread can initiate a purchase request at a time , So when a thread reduces the inventory to 0 When , The second request cannot be modified , This ensures the accuracy of the data .
Code implementation
So in Python among , How can we implement this lock ?
It's very simple ,threading The library has provided us with threading tools , We can just take it and use it . We use threading In the middle of Lock object , It can easily realize the function of locking .
import threading
class PurchaseRequest:
'''
Initialize inventory and lock
'''
def __init__(self, initial_value = 0):
self._value = initial_value
self._lock = threading.Lock()
def incr(self,delta=1):
'''
Add inventory
'''
self._lock.acquire()
self._value += delta
self._lock.release()
def decr(self,delta=1):
'''
Reduce inventory
'''
self._lock.acquire()
self._value -= delta
self._lock.release()
We can easily see from the code Lock How to use this object , We are entering the locked area ( Resource preemption area ) Before , We need to use lock.acquire() Method to acquire lock .Lock Object can ensure that only one thread can acquire a lock at a time , Only after obtaining the lock will the execution continue . When we finish the execution , We need to lock “ Put it back at the door ”, So you need to call again release Method , Indicates the release of the lock .
A small problem here is that many programmers always forget when programming release, Lead to unnecessary bug, And in this distributed scenario bug It's hard to find through testing . Because it is often difficult to test concurrent scenarios ,code review It's also easy to ignore , Therefore, once it is leaked, it is still very difficult to find .
To solve this problem ,Lock An improved usage is also provided , Is the use of with sentence .with Statement we have used before when using files , Use with You can finish it for us try catch And resource recovery , We'll be done if it works . Same thing here , Use with Then we can apply and release the lock without any care , Just write the code , So the above code can be rewritten like this :
import threading
class PurchaseRequest:
'''
Initialize inventory and lock
'''
def __init__(self, initial_value = 0):
self._value = initial_value
self._lock = threading.Lock()
def incr(self,delta=1):
'''
Add inventory
'''
with self._lock:
self._value += delta
def decr(self,delta=1):
'''
Reduce inventory
'''
with self._lock:
self._value -= delta
Does it look so refreshing ?
Reentrant lock
The above description is only the simplest lock , We often use reentrant locks .
What is a reentrant lock ? A brief explanation , When a thread already holds a lock , It can enter the locked area again . But since the thread still holds the lock, it has not been released , Shouldn't it still be in the locked area , How can it be necessary to enter the locked area again ? There is , It's also very simple , It's recursion .
Let's change the above example a little , It's totally different .
import threading
class PurchaseRequest:
'''
Initialize inventory and lock
'''
def __init__(self, initial_value = 0):
self._value = initial_value
self._lock = threading.Lock()
def incr(self,delta=1):
'''
Add inventory
'''
with self._lock:
self._value += delta
def decr(self,delta=1):
'''
Reduce inventory
'''
with self._lock:
self.incr(-delta)
Let's pay attention to the above decr Method , We use it incr Instead of the original logic implementation decr. But there is a problem decr It is also a locking method , You need to release the previous lock to enter . But it already holds the lock , Then a deadlock will occur in this case .
We just have to take Lock This problem can be solved by replacing it with a reentrant lock , Just change one line of code .
import threading
class PurchaseRequest:
'''
Initialize inventory and lock
We use RLock Instead of Lock, The re-entry lock also replaces the ordinary lock
'''
def __init__(self, initial_value = 0):
self._value = initial_value
self._lock = threading.RLock()
def incr(self,delta=1):
'''
Add inventory
'''
with self._lock:
self._value += delta
def decr(self,delta=1):
'''
Reduce inventory
'''
with self._lock:
self.incr(-delta)
summary
Today's article introduces Python How to use the middle lock , And the concept of reentrant lock . Developing and debugging in concurrent scenarios is a difficult job , If you are not careful, you will step into all kinds of pits , Deadlock is just one of the more common and easy to solve problems , In addition, there are many other kinds of problems .
The above is all the content shared this time , Want to know more python Welcome to official account :Python Programming learning circle , send out “J” Free access to , Daily dry goods sharing