多線程
t=threading.Thread(target=task,arge=(11,))
start()開始
join()等待
主線程在默認情況下會等待所有非守護線程(子線程)結束后才會結束程序。也就是說,如果主線程在結束前沒有調用所有子線程的 join()
方法,主線程將繼續執行,并且當主線程完成它的執行后,它將等待所有子線程結束。
多線程對同一個變量操作時可能造成數據競爭
import threading
loop=1000000
number=0
def _add(count):global numberfor i in range(count):number+=1
def _sub(count):global numberfor i in range(count):number-=1
t1=threading.Thread(target=_add,args=(loop,))
t2=threading.Thread(target=_sub,args=(loop,))
t1.start()
t2.start()
t1.join()
#t2.join()
print(number)
未調用 t2.join()
會導致在 t1
線程結束后,主線程打印 number
的值,然后程序依然會等 t2
線程結束。但由于打印 number
的操作在 t2
結束前可能被執行,這會導致 number
的值不確定。
解決方案:
加鎖
import threading
loop=1000000
number=0
lock_object=threading.RLock()
def _add(count):lock_object.acquire() #申請鎖global numberfor i in range(count):number+=1lock_object.release() # 釋放鎖
def _sub(count):lock_object.acquire()global numberfor i in range(count):number-=1lock_object.release()
# 也可以這么寫
def sub():with lock_object: #自動進行申請和釋放global numberfor i in range(count):number-=1
t1=threading.Thread(target=_add,args=(loop,))
t2=threading.Thread(target=_sub,args=(loop,))
t1.start()
t2.start()
t1.join()
t2.join()
print(number)
Lock(同步鎖)和 RLock(遞歸鎖)區別
Lock效率更高,但是不支持多次鎖的情況,一般項目開發還是用RLock
import threading
lock_object=threading.RLock()# personA create a function
def fun():with lock_object:pass
# personB,too and use A' fun()
def run():print("other use")fun()print("other use")
# personC create functions,need lock,use fun
def progress():with lock_object:print('other use')fun()print('hhhhh')
死鎖
競爭資源
import threading
lock=threading.RLock()
num=0
def task():print('start')lock.acquire()lock.acquire()global numfor i in range(100000):num+=ilock.release()lock.release()print(num)
for i in range(2):t=threading.Thread(target=task)t.start()
# start
# 4999950000
# start
# 9999900000
彼此通信
import threading
import time
lock_1=threading.RLock()
lock_2=threading.RLock()
def task1():lock_1.acquire()time.sleep(1)lock_2.acquire()print(11)lock_2.release()print(1111)lock_1.release()print(111111)
def task2():lock_2.acquire()time.sleep(1)lock_1.acquire()print(22)lock_1.release()print(2222)lock_2.release()print(222222)
t1=threading.Thread(target=task1)
t1.start()
t2=threading.Thread(target=task2)
t2.start()