Python 之并发编程之线程中
四.线程锁lock(线程的数据安全)
在数据量较大的时候,线程中的数据会被并发,所有数据会不同步,以至于数据会异常。
下面还介绍了两种的上锁方法。
例:
from threading import Thread, Lock
import time
n = 0
def func1(lock):
global n
# time.sleep(0.3)
# print(11)
for i in range(10000):
# 正常上锁
lock.acquire()
print(n)
n -= 1
lock.release()
def func2(lock):
global n
# time.sleep(0.3)
# print(22)
for i in range(10000):
# 用with 自动上锁解锁
with lock:
print(n)
n += 1
if __name__ == "__main__":
# 创建一个锁
lock = Lock()
lst = []
for i in range(10):
t1 = Thread(target=func1, args=(lock,))
t2 = Thread(target=func2, args=(lock,))
t1.start()
t2.start()
lst.append(t1)
lst.append(t2)
for i in lst:
i.join()
print("主线程执行语句结束")
print(n) # n最后得0,如果没有加上锁的话,不会是0
# 程序执行结束
五.线程的信号量
例:效果是5个一打印,5个一打印
from threading import Semaphore, Thread
import time, random
def func(i, sem):
# with简写
with sem:
print(i)
time.sleep(random.uniform(0.1, 1))
"""
# 正常写法
sem.acquire()
print(i)
time.sleep(random.uniform(0.1,1))
sem.release()
"""
if __name__ == "__main__":
sem = Semaphore(5) # 设置几个线程同时运行几个
for i in range(50):
Thread(target=func, args=(i, sem)).start()
六.线程的锁
1.死锁
例:只有拿到筷子和面才能吃
noodle_lock = Lock()
chopsticks_lock = Lock()
def eat1(name):
noodle_lock.acquire()
print("%s拿到面条" % (name))
chopsticks_lock.acquire()
print("%s拿到筷子" % (name))
print("开始吃")
time.sleep(0.7)
chopsticks_lock.release()
print("%s放下筷子" % (name))
noodle_lock.release()
print("%s放下面条" % (name))
def eat2(name):
chopsticks_lock.acquire()
print("%s拿到筷子" % (name))
noodle_lock.acquire()
print("%s拿到面条" % (name))
print("开始吃")
time.sleep(0.6)
noodle_lock.release()
print("%s放下面条" % (name))
chopsticks_lock.release()
print("%s放下筷子" % (name))
if __name__ == "__main__":
name_list1 = ["one", "two"]
name_list2 = ["three", "four"]
for name in name_list1:
Thread(target=eat1, args=(name,)).start()
for name in name_list2:
Thread(target=eat2, args=(name,)).start()
# 双方都在等待,造成死锁的现象.
2.递归锁RLock
递归锁专门用来解决死锁现象
临时用于快速解决服务器崩溃的异常现象,用递归锁应急
解决应急问题的
(1)基本用法
from threading import Thread,RLock
# 递归锁如果3个,就对于释放3分锁,忽略上锁过程,进行解锁
rlock = RLock()
def func(name):
rlock.acquire()
print(name,1)
rlock.acquire()
print(name,2)
rlock.acquire()
print(name,3)
rlock.release()
rlock.release()
rlock.release()
lst = []
for i in range(10):
t1 = Thread(target=func,args=("name%s" % (i), ))
t1.start()
lst.append(t1)
for i in lst:
i.join()
print("程序结束了")
(2)用递归锁应急解决死锁现象
# 用递归锁应急解决死锁现象
noodle_lock = chopsticks_lock = RLock()
def eat1(name):
noodle_lock.acquire()
print("%s拿到面条" % (name))
chopsticks_lock.acquire()
print("%s拿到筷子" % (name))
print("开始吃")
time.sleep(0.7)
chopsticks_lock.release()
print("%s放下筷子" % (name))
noodle_lock.release()
print("%s放下面条" % (name))
def eat2(name):
chopsticks_lock.acquire()
print("%s拿到筷子" % (name))
noodle_lock.acquire()
print("%s拿到面条" % (name))
print("开始吃")
time.sleep(0.6)
noodle_lock.release()
print("%s放下面条" % (name))
chopsticks_lock.release()
print("%s放下筷子" % (name))
if __name__ == "__main__":
name_list1 = ["one", "two"]
name_list2 = ["three", "four"]
for name in name_list1:
Thread(target=eat1, args=(name,)).start()
for name in name_list2:
Thread(target=eat2, args=(name,)).start()
3.互斥锁
从语法上来看,锁是可以互相嵌套的,但是不要使用
上一次锁,就对应解开一把锁,形成互斥锁
吃面条和拿筷子是同时的,上一次锁就够了,不要分别上锁
尽量不要形成锁的嵌套,容易死锁
例:
from threading import Thread,RLock
mylock = Lock()
def eat1(name):
mylock.acquire()
print("%s拿到面条" % (name))
print("%s拿到筷子" % (name))
print("开始吃")
time.sleep(0.7)
print("%s放下筷子" % (name))
print("%s放下面条" % (name))
mylock.release()
def eat2(name):
mylock.acquire()
print("%s拿到筷子" % (name))
print("%s拿到面条" % (name))
print("开始吃")
time.sleep(0.6)
print("%s放下面条" % (name))
print("%s放下筷子" % (name))
mylock.release()
if __name__ == "__main__":
name_list1 = ["one", "two"]
name_list2 = ["three", "four"]
for name in name_list1:
Thread(target=eat1, args=(name,)).start()
for name in name_list2:
Thread(target=eat2, args=(name,)).start()