python多线程锁lock/Rlock/BoundedSemaphore/Condition/Event

时间:2024-01-07 15:29:02
import time
import threading lock = threading.RLock() n = 10 def task(arg):
# 加锁,此区域的代码同一时刻只能有一个线程执行
lock.acquire() # 获取当前线程对象
thread_obj = threading.current_thread()
# 获取当前线程名字
name = thread_obj.getName() global n
n = arg
time.sleep(1)
print('当前线程', name, '修改后n的值为:', n) # 释放锁
lock.release() for i in range(5):
t = threading.Thread(target=task, args=(i,))
t.setName(str(i))
t.start()

'''

期望结果-->加锁情况:

当前线程 0 修改后n的值为: 0

当前线程 1 修改后n的值为: 1

当前线程 2 修改后n的值为: 2

当前线程 3 修改后n的值为: 3

当前线程 4 修改后n的值为: 4

'''

'''

不期望结果-->没加锁情况

当前线程 0 修改后n的值为: 4

当前线程 1 修改后n的值为: 4

当前线程 2 修改后n的值为: 4

当前线程 3 修改后n的值为: 4

当前线程 4 修改后n的值为: 4

'''

引子:为什么要加锁?

需求:每个线程将一个数字添加到列表,然后取出自己放的数字,线程结束.

希望得到的结果如下:

'''

0 0

1 1

2 2

3 3

4 4

'''

代码:

import threading

import time

lst = []

def func(arg):

# 线程安全

lst.append(arg)

time.sleep(0.1)

m = lst[-1]

print(arg,m)

for i in range(5):

t = threading.Thread(target=func,args=(i,))

t.start()

总结:

从上面这个例子看,如果不加锁,每个线程放进去自己的数字,再取最后一个数字,就不一定是自己放的,因为这个时间,可能其他线程也放进去了,你拿到的,可能是其他线程放的.所以这个时候就需要加锁,限制一个线程没操作完,另一个绝对不能动.

1.锁:Lock(1次放1个)

import threading

import time

lst = []

lock = threading.Lock()

def func(arg):

lock.acquire()

lst.append(arg)

time.sleep(0.1)

m = lst[-1]

lock.release()

for i in range(5):

t = threading.Thread(target=func,args=(i,))

t.start()

2.锁:RLock(1次放1个)

import threading
import time lst = []
lock = threading.RLock() def func(arg):
lock.acquire()
lock.acquire()
lst.append(arg)
time.sleep(0.1)
m = lst[-1]
print(arg, m)
lock.release()
lock.release() for i in range(5):
t = threading.Thread(target=func, args=(i,))
t.start()

PS:Lock和RLock的区别是RLock可以多次加锁.

3.锁:BoundedSemaphore(1次放N个)信号量

import time
import threading lst = []
# 一次放3个
lock = threading.BoundedSemaphore(3) def func(arg):
lock.acquire()
lst.append(arg)
m = lst[-1]
print(arg, m)
time.sleep(3)
lock.release() for i in range(10):
t = threading.Thread(target=func, args=(i,))
t.start()

4.锁:Condition(1次放x个)

方法1:

import time
import threading lst = []
lock = threading.Condition() def func(arg):
print('start...')
lock.acquire()
lock.wait()
lst.append(arg)
m = lst[-1]
print(arg, m)
time.sleep(1)
lock.release() for i in range(10):
t = threading.Thread(target=func, args=(i,))
t.start() while True:
num = int(input('>>>:'))
lock.acquire()
# 控制放几个线程执行,比如写3个,但是线程实际2个,那就是2个了
lock.notify(num) # 3
lock.release()

方法2:

import time
import threading lock = threading.Condition() def func1():
print('start...')
input('>>>:')
return True def func2(arg):
print('\n线程进来了')
# func1作为执行条件
lock.wait_for(func1)
print(arg)
time.sleep(1) for i in range(10):
t = threading.Thread(target=func2, args=(i,))
t.start()

5.锁:Event(1次放所有)

import threading

lock = threading.Event()

def func(arg):
print('线程来了')
# 加锁:红灯
lock.wait()
print(arg) for i in range(10):
t = threading.Thread(target=func, args=(i,))
t.start()
input('>>>:')
lock.set() # 绿灯
lock.clear() # 再次变红灯 for i in range(10):
t = threading.Thread(target=func, args=(i,))
t.start()
input('>>>')
lock.set()

总结:

线程安全,列表和字典线程安全;

为什么要加锁?

- 非线程安全

- 控制一段代码