程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python learning --- thread lock / semaphore / condition variable synchronization / thread pool 1221

編輯:Python

Python Study --- Thread lock / Semaphore / Conditional variable synchronization


Thread lock

Problem phenomenon :​ multithreading ,CPU When blocking occurs, the thread will be switched , So it leads to execution tmp-=1 The value of has not been assigned to num=tmp, Another thread 2 It started again tmp -=1, So the last value is assigned to num, So it's here final num Not 0 The situation of .[time.sleep(0.000.) The shorter the break , The smaller the final value ]

import time

import threading
def addNum():
global num # Get this global variable in each thread
temp=num
print('--get num:',num )
time.sleep(0.00000001)
temp -= 1
num = temp
num = 100 # Set a shared variable
thread_list = []
lock=threading.Lock()
for i in range(100):
t = threading.Thread(target=addNum)
t.start()
thread_list.append(t)
for t in thread_list: # Wait for all threads to finish executing
t.join()
print('final num:', num )
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.


Problem solving : Synchronization lock

Classification of locks :


              Synchronization lock : Make sure that one thread is using the shared resource at every moment , Avoid the generation of dirty data

              die   lock : Threads wait for each other to be released

              Recursive lock : It consists of an internal timer and a lock , Can be reused , Every use count+1, Release once -1


Synchronization lock :


           lock.acquire()   # Gets the lock

           lock.release()  # Release the lock


import threading

def addNum():
global num # Get this global variable in each thread
# num-=1
lock.acquire() # Gets the lock
temp=num
print('--get num:',num )
#time.sleep(0.1)
num =temp-1 # For this common variable -1 operation
lock.release() # Release the lock
num = 100 # Set a shared variable
thread_list = []
lock=threading.Lock()
for i in range(100):
t = threading.Thread(target=addNum)
t.start()
thread_list.append(t)
for t in thread_list: # Wait for all threads to finish executing
t.join()
print('final num:', num )
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.

​​

[ Thread analysis --- Picture from the Internet ]

​​


Deadlock :​ AB At the same time, it is locked , Wait for the other party to release the lock

          terms of settlement : Use recursive locks

import time

import threading
class MyThread(threading.Thread):
def doA(self):
lockA.acquire()
print(self.name, "gotlockA", time.ctime())
time.sleep(3)
lockB.acquire()
print(self.name, "gotlockB", time.ctime())
lockB.release()
lockA.release()
def doB(self):
lockB.acquire()
print(self.name,"gotlockB",time.ctime())
time.sleep(2)
lockA.acquire()
print(self.name,"gotlockA",time.ctime())
lockA.release()
lockB.release()
def run(self):
self.doA()
self.doB()
if __name__ == '__main__':
lockA = threading.Lock()
lockB = threading.Lock()
threads = []
for i in range(5):
threads.append(MyThread())
for i in threads:
i.start()
for i in threads:
i.join()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.

​​

Recursive lock : ​ Reusable locks   [ timer + lock ]

import time

import threading
class MyThread(threading.Thread):
def doA(self):
lock.acquire() # Perform an operation , Lock the thread with a lock
print(self.name, "gotlockA", time.ctime())
time.sleep(3)
lock.acquire() # Perform an operation , Lock the thread with a lock
print(self.name, "gotlockB", time.ctime())
lock.release()
lock.release()
def doB(self):
lock.acquire()
print(self.name,"gotlockB",time.ctime())
time.sleep(2)
lock.acquire()
print(self.name,"gotlockA",time.ctime())
lock.release()
lock.release()
def run(self):
self.doA()
self.doB()
if __name__ == '__main__':
lock = threading.RLock()
threads = []
for i in range(5):
threads.append(MyThread())
for i in threads:
i.start()
for i in threads:
i.join()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.

​​

ask : Why? RLock There's another one in it Rlock? 

answer :​1. Prevent other functions from calling data operated functions , cause 2 Data is being written , Generating dirty data

      2. It reduces repeated lock operations in other functions to avoid dirty data

import time

import threading
class Account:
def __init__(self, money, id):
self.account = id
self.balance = money
self.r = threading.RLock() # It should be that everyone has his own lock

def add(self, num): # 2 You can add a lock on the method to solve the problem of dirty data caused by other function calls
self.r.acquire()
self.balance += num
self.r.release()
def adwithdrd(self, num):
self.r.acquire()
self.balance -= num
self.r.release()
# def diy(self, num): # 3 It is also a repeated call in a class , That's why there are Rlock Repeated calls to
# self.r.acquire()
# self.balance -= num
# self.adwithdrd(num)
# self.r.release()
def __str__(self):
print(self.balance, self.account)
a1 = Account(500, 'A')
b1 = Account(300, 'B')
# def user_trans(A, B, num):
# A.adwithdrd(num)
# B.add(num) # 1 If a thread operates this function , Will perform add Method , Will affect the final data , The best solution is to add a lock to the class
def trans(A, B, num):
r = threading.RLock()
r.acquire()
A.adwithdrd(num)
B.add(num)
r.release()
t1 = threading.Thread(target=trans, args=(a1, b1, 100))
t3 = threading.Thread(target=trans, args=(a1, b1, 100))
t2 = threading.Thread(target=trans, args=(b1, a1, 200))

t1.start()
t2.start()
t3.start()
a1.__str__()
b1.__str__()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.

Semaphore :

A semaphore used to control the number of concurrent threads ,BoundedSemaphore or Semaphore Manage a built-in count device , Whenever you call acquire() when -1, call release() when +1.

Counter must not be less than 0, When the counter is 0 when ,acquire() Puts the blocked thread into a synchronously locked state , Until another thread calls it release().( Similar to the concept of parking Spaces )

      BoundedSemaphore And Semaphore The only difference is that the former will be invoked release() Time check count Whether the value of the counter exceeds the initial value , An exception is thrown if it exceeds

application : Database connection pool

import threading,time

class myThread(threading.Thread):
def run(self):
if semaphore.acquire():
print(self.name)
time.sleep(5)
semaphore.release()
if __name__=="__main__":
semaphore=threading.Semaphore(5)
thrs=[]
for i in range(100):
thrs.append(myThread())
for t in thrs:
t.start()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

Thread pool

Conditional variable synchronization 1223

There is a class of threads that need to meet the conditions before they can continue to execute ,Python Provides threading.Condition Object is used to support conditional variable threads , In addition to providing RLock() or Lock() Out of the way , It also provides wait()、notify()、notifyAll() Method .

      lock_con=threading.Condition([Lock/Rlock]): Locks are optional , Do not pass in locks , Object automatically creates a RLock().

application : Used for information exchange between threads


wait(): Called when conditions are not met , The thread releases the lock and enters a wait block ;

notify(): Call after condition creation , Notify the wait pool to activate a thread ;

notifyAll(): Call after condition creation , Notify the wait pool to activate all threads


import threading,time

from random import randint
class Producer(threading.Thread):
def run(self):
global L
while True:
val=randint(0,100)
print(' producer ',self.name,":Append"+str(val),L)
if lock_con.acquire():
L.append(val)
lock_con.notify() # notify No ability to release lock , So you need to release it manually
lock_con.release() # Release the lock manually
time.sleep(3)
class Consumer(threading.Thread):
def run(self):
global L
while True:
lock_con.acquire() # Get the lock back
if len(L)==0:
lock_con.wait() # wait Enter wait and release lock
print(' consumer ',self.name,":Delete"+str(L[0]),L)
del L[0]
lock_con.release()
time.sleep(0.25)

if __name__=="__main__":

L=[]
lock_con=threading.Condition()
threads=[]
for i in range(5):
threads.append(Producer())
threads.append(Consumer())
for t in threads:
t.start()
for t in threads:
t.join()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.

​​


author :​​ Small a ninety-seven ​​​ ​

-------------------------------------------

Individuality signature : Everything is good in the end , If it's not good , That means things haven't come to the end yet ~

The copyright of this article belongs to the author 【​​ Small a ninety-seven ​​​】, Welcome to reprint , However, this statement must be retained without the consent of the author , And in the article page obvious position gives the original link , Otherwise, the right to pursue legal responsibility is reserved !




  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved