【Python3 爬虫】U26_多线程爬虫之生产者与消费者模式
生产者消费者模型是多线程开发中经常见到的一种模式。生产者专门生产一些数据,把这些数据放到变量中,消费者从变量中取出一些数据来消费。由于要使用到中间变量,这些变量一般是全局变量,所以使用使用锁机制来保证数据的完整性。就好比老爸去工作赚钱存在银行,儿子从银行取钱来花,老爸是生产者,银行就是中间变量,儿子是消费者。
1.Lock版生产者与消费者模型
import time
import threading
import random
g_money = 1000
g_lock = threading.Lock()
g_total_times = 10
g_times = 0
class Producer(threading.Thread):
def run(self):
global g_money
global g_times
while True:
money = random.randint(100,1000)
g_lock.acquire()
if g_times >= g_total_times: # 生产者生产10次就停止
g_lock.release()
break
g_money += money
print('%s生产者生产了%d元,剩余%d元' %(threading.current_thread(),money,g_money))
g_times += 1
g_lock.release()
time.sleep(1)
class Consumer(threading.Thread):
def run(self):
global g_money
global g_times
while True:
money = random.randint(100, 1000)
g_lock.acquire()
if g_money >= money: # 当剩余的钱大于消费者需要消费的金额的时候,才可以消费
g_money -= money
print('%s消费者消费了%d元,剩余%d元' % (threading.current_thread(), money, g_money))
else:
# 在if条件中已经判断金钱是否够消费,此处还需要判断,如果生产者生产的次数已经完了,那么消费者也别在这干等了,没有钱会被生产了
if g_times >= g_total_times:
g_lock.release()
break
print("%s消费者准备消费%d元,剩余%d元,余额不足了!你还消费个锤子!" %(threading.current_thread(), money, g_money))
g_lock.release()
time.sleep(1)
def main():
for i in range(3):
t = Producer()
t.start()
for i in range(4):
t = Consumer()
t.start()
if __name__ == '__main__':
main()
以下是其中一次运行结果截图:
2.condition版的生产者与消费者模型
Lock版本的生产者与消费者模型可以正常运行,但是存在一个缺点,在消费者中,总是while True死循环上锁的方式去判断钱够不够,这样很耗费资源的。上锁本身就比较耗费CPU资源,因此这种实现是不理想的。那么就可以使用threading.condition
来实现。threading.condition
在没有数据的时候处于阻塞等待状态。一旦有合适的数据了,还可以使用notify
相关的函数来通知其他处于等待状态的线程。这样就可以少做一些无用的上锁和解锁操作,提高程序性能。
以下是threading.condition
常用函数介绍:
- acquire:上锁
- release:解锁
- wait:将线程处于等待状态,并且会释放锁。可以被其他线程使用
notify
和notify_all
函数唤醒。被唤醒后会继续等待上锁,上锁后继续还行下面的代码。 - notify:通知某个正在等待的线程,默认是第一个线程。
- notify_all:通知正在等待的线程。notify不会与notify_all不会释放锁,需要在release之前调用。
示例代码如下:
# Author:Logan
import time
import threading
import random
g_money = 1000
g_condition = threading.Condition()
g_total_times = 10
g_times = 0
class Producer(threading.Thread):
def run(self):
global g_money
global g_times
while True:
money = random.randint(100,1000)
g_condition.acquire()
if g_times >= g_total_times: # 生产者生产10次就停止
g_condition.release()
break
g_money += money
print('%s生产者生产了%d元,剩余%d元' %(threading.current_thread(),money,g_money))
g_times += 1
g_condition.notify_all()
g_condition.release()
time.sleep(1)
class Consumer(threading.Thread):
def run(self):
global g_money
global g_times
while True:
money = random.randint(100, 1000)
g_condition.acquire()
while g_money < money: # 当消费的钱大于现有的钱,并且生产者还在生产钱的情况下,则处于等待
if g_times >= g_total_times:
g_condition.release()
return
print("%s消费者准备消费%d元,剩余%d元,余额不足了!你还消费个锤子!" % (threading.current_thread(), money, g_money))
g_condition.wait()
g_money -= money
print('%s消费者消费了%d元,剩余%d元' % (threading.current_thread(), money, g_money))
g_condition.release()
time.sleep(1)
def main():
for i in range(3):
t = Producer()
t.start()
for i in range(4):
t = Consumer()
t.start()
if __name__ == '__main__':
main()
其中一次运行结果如下:
作者:奔跑的金鱼
声明:书写博客不易,转载请注明出处,请支持原创,侵权将追究法律责任
个性签名:人的一切的痛苦,本质上都是对自己无能的愤怒
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!