某些模块负责生产数据,这些数据由其余模块来负责处理(此处的模块多是:函数、线程、进程等)。产生数据的模块称为生产者,而处理数据的模块称为消费者。在生产者与消费者之间的缓冲区称之为仓库。生产者负责往仓库运输商品,而消费者负责从仓库里取出商品,这就构成了生产者消费者模式。python
解耦
假设生产者和消费者分别是两个线程。若是让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。若是将来消费者的代码发生变化,可能会影响到生产者的代码。而若是二者都依赖于某个缓冲区,二者之间不直接依赖,耦合也就相应下降了。并发
并发
因为生产者与消费者是两个独立的并发体,他们之间是用缓冲区通讯的,生产者只须要往缓冲区里丢数据,就能够继续生产下一个数据,而消费者只须要从缓冲区拿数据便可,这样就不会由于彼此的处理速度而发生阻塞。app
#!/usr/bin/python # -*- coding: utf-8 -*- # @Time : 2017/12/4 16:29 # @Author : YuLei Lan # @Email : lanyulei@renrenche.com # @File : urls.py # @Software: PyCharm import requests import os from urllib.request import urlretrieve from bs4 import BeautifulSoup import threading BASE_PAGE_URL = 'http://www.doutula.com/photo/list/?page=' PAGE_URL_LIST = [] # 全部分页的列表 FACE_URL_LIST = [] # 全部表情的url列表 gLock = threading.Lock() def get_page_url(): for i in range(1, 2): url = BASE_PAGE_URL + str(i) PAGE_URL_LIST.append(url) def procuder(): """ 生产者 不断生产出全部的可下载的img_url地址 """ while len(PAGE_URL_LIST) != 0: # 不能使用for循环 gLock.acquire() page_url = PAGE_URL_LIST.pop() gLock.release() response = requests.get(page_url) text = response.text soup = BeautifulSoup(text, 'lxml') img_list = soup.find_all('img', attrs={'class': 'img-responsive lazy image_dta'}) gLock.acquire() for img in img_list: img_url = img['data-original'] if not img_url.startswith('http:'): img_url = 'http:{}'.format(img_url) FACE_URL_LIST.append(img_url) gLock.release() def customer(): """ 消费者 """ while True: if len(FACE_URL_LIST) == 0: continue else: img_url = FACE_URL_LIST.pop() tmp_list = img_url.split('/') filename = tmp_list.pop() path_file = os.path.join('images', filename) urlretrieve(img_url, filename=path_file) def main(): for i in range(3): th = threading.Thread(target=procuder) th.start() for i in range(5): th = threading.Thread(target=customer) th.start() if __name__ == '__main__': get_page_url() main()