多线程同步问题
- 一、线程中的资源竞争
- 二、死锁
- 三、Queue线程(队列)
- 四、线程同步
- 五、生产者和消费者
-
- 5.1 Lock版的生产者和消费者
- 5.2 Condition版的生产者和消费者
一、线程中的资源竞争
import threading
import time
num = 0
# 创建一把锁 默认是没有上锁
suo=threading.Lock()
def demo1(nums):
global num
# 加锁
suo.acquire()
for i in range(nums):
num += 1
# 解锁
suo.release()
print('demo1-num %d'%num)
def demo2(nums):
global num
# 加锁
suo.acquire()
for i in range(nums):
num += 1
# 解锁
suo.release()
print('demo2-num %d'%num)
def main():
t1=threading.Thread(target=demo1,args=(1000000,))
t2=threading.Thread(target=demo2,args=(1000000,))
t1.start()
# t1.join()
# time.sleep(1)
t2.start()
# t1.join()
time.sleep(1)
print('demo-num %d'%num)
if __name__ == '__main__':
main()
threading.Lock() 只能创建一次
threading.RLock() 可创建多次,需逐个解锁
二、死锁
import threading
import time
class MyThread1(threading.Thread):
def run(self):
# 对mutexA上锁
mutexA.acquire()
# mutexA上锁后,延时1秒,等待另外那个线程 把mutexB上锁
print(self.name+'----do1---up----')
time.sleep(1)
# 此时会堵塞,因为这个mutexB已经被另外的线程抢先上锁了
mutexB.acquire()
print(self.name+'----do1---down----')
mutexB.release()
# 对mutexA解锁
mutexA.release()
class MyThread2(threading.Thread):
def run(self):
# 对mutexB上锁
mutexB.acquire()
# mutexB上锁后,延时1秒,等待另外那个线程 把mutexA上锁
print(self.name+'----do2---up----')
time.sleep(1)
# 此时会堵塞,因为这个mutexA已经被另外的线程抢先上锁了
mutexA.acquire()
print(self.name+'----do2---down----')
mutexA.release()
# 对mutexB解锁
mutexB.release()
mutexA = threading.Lock()
mutexB = threading.Lock()
if __name__ == '__main__':
t1 = MyThread1()
t2 = MyThread2()
t1.start()
t2.start()
# Thread-1----do1---up----
# Thread-2----do2---up----
三、Queue线程(队列)
队列:先进先出
empty():判断队列是否为空
full():判断队列是否满了
from queue import Queue
q=Queue(3)
print(q.empty()) # True 空的队列 False 不是空的队列
print(q.full()) # True 满的队列 False 不是满的队列
put():将一个数据放到队列中
q.put(1)
q.put(2)
q.put(3)
q.put(4,timeout=3) # 队列已满,溢出,报错
# 或 q.put_nowait(4)
get():从队列中取最后一个数据
print(q.get()) # 1
print(q.get()) # 2
print(q.get()) # 3
print(q.get(timeout=3)) # 队列已空,报错
# 或 print(q.get_nowait())
四、线程同步
张三:李四同学
李四:在
张三:现在几点了?
李四:不知道!
import threading
创建2个线程
class ZhangSan(threading.Thread):
def __init__(self,cond):
super().__init__(name='张三')
self.cond=cond
def run(self):
self.cond.acquire() # 加锁
print('{}:李四同学'.format(self.name))
self.cond.notify() # 唤醒
self.cond.wait() # 等待
print('{}:现在几点了?'.format(self.name))
self.cond.notify() # 唤醒
self.cond.release() # 解锁
class LiSi(threading.Thread):
def __init__(self,cond):
super().__init__(name='李四')
self.cond=cond
def run(self):
self.cond.acquire() # 加锁
self.cond.wait() # 等待
print('{}:在'.format(self.name))
self.cond.notify() # 唤醒
self.cond.wait() # 等待
print('{}:不知道!'.format(self.name))
self.cond.release() # 解锁
if __name__ == '__main__':
cond=threading.Condition()
lisi=LiSi(cond)
zhangsan=ZhangSan(cond)
lisi.start()
zhangsan.start()
五、生产者和消费者
生产者和消费者模式是多线程开发中常见的一种模式。通过生产者和消费者模式,可以让代码达到高内聚低耦合的目标,线程管理更加方便,程序分工更加明确。
5.1 Lock版的生产者和消费者
import threading
import random
import time
Gmoney=0
# 定义一个变量,保存生产的次数
Gtime=0
# 定义一把锁
lock=threading.Lock()
# 定义生产者
class Producer(threading.Thread):
def run(self) -> None:
global Gmoney
global Gtime
while True:
lock.acquire() # 加锁
if Gtime >= 10:
lock.release() # 解锁
break
money = random.randint(0, 100)
Gmoney += money
Gtime += 1
print('%s生产了%d元钱' % (threading.current_thread().name, money))
lock.release()
time.sleep(1)
# 定义消费者
class Consumer(threading.Thread):
def run(self) -> None:
global Gmoney
global Gtime
while True:
lock.acquire() # 加锁
money = random.randint(0, 100)
if Gmoney >= money:
Gmoney -= money
print('%s消费了%d元钱' % (threading.current_thread().name, money))
else:
if Gtime >= 10:
lock.release() # 解锁
break
print('%s消费了%d元钱,余额只有%d' % (threading.current_thread().name, money, Gmoney))
lock.release()
time.sleep(1)
def main():
# 开启5个生产者
for i in range(5):
p=Producer(name='生产者%d号'%i)
p.start()
# 开启5个消费者
for j in range(5):
c=Consumer(name='消费者%d号'%j)
c.start()
if __name__ == '__main__':
main()
5.2 Condition版的生产者和消费者
import threading
import random
import time
Gmoney=0
# 定义一个变量,保存生产的次数
Gtime=0
cond=threading.Condition()
# 定义生产者
class Producer(threading.Thread):
def run(self) -> None:
global Gmoney
global Gtime
while True:
cond.acquire() # 加锁
if Gtime >= 10:
cond.release() # 解锁
break
money = random.randint(0, 100)
Gmoney += money
Gtime += 1
print('%s生产了%d元钱,剩余%d元' % (threading.current_thread().name, money,Gmoney))
cond.notify_all() # 唤醒所有
cond.release()
time.sleep(1)
# 定义消费者
class Consumer(threading.Thread):
def run(self) -> None:
global Gmoney
global Gtime
while True:
cond.acquire() # 加锁
money = random.randint(0, 100)
while Gmoney < money:
if Gtime >= 10:
cond.release()
return # 这里如果用break退出了内层循环,但是外层循环没有退出,直接用return
print('%s消费者消费了%d元,余额%d元,生产者不再生成了'%(threading.current_thread().name,money,Gmoney))
cond.wait()
# 开始消费
Gmoney -= money
print('%s消费了%d元钱,剩余%d元' % (threading.current_thread().name, money,Gmoney))
cond.release()
time.sleep(1)
def main():
# 开启5个生产者
for i in range(5):
p=Producer(name='生产者%d号'%i)
p.start()
# 开启5个消费者
for j in range(5):
c=Consumer(name='消费者%d号'%j)
c.start()
if __name__ == '__main__':
main()