(十)异步调用与回调机制
一、同步调用
提交任务有两种方式:同步调用,异步调用。
同步调用:提交完任务后,就在原地等待任务执行完毕,拿到结果再执行下一行代码,导致程序是串行执行。
例子:今年你们公司开年会,举办了一个吃汉堡大赛,然后把计算下大家一共吃了多少个,谁的最多,谁发的年终奖就最多。
# 1,同步调用:提交完任务后,就在原地等待任务执行完毕,拿到结果再执行下一行代码,导致程序是串行执行。 from concurrent.futures import ThreadPoolExecutor import time,random def eat(name): print("%s 正在吃。" % name) time.sleep(random.randint(3,5)) # 吃的时间 res = random.randint(7,13) # 吃了几个 return {"name":name,"res":res} def count(hamburger): name = hamburger["name"] num = hamburger["res"] print("%s 吃了《%s》个。" % (name,num)) if __name__ == '__main__': pool = ThreadPoolExecutor(3) # 参赛人数,用线程池 shit1 = pool.submit(eat,"托儿所").result() # 提交任务,等待任务执行完毕,拿到结果 count(shit1) shit2 = pool.submit(eat,"儿童劫").result() count(shit2) shit3 = pool.submit(eat,"瑞萌萌").result() count(shit3) """ 托儿所 正在吃。 托儿所 吃了《8》个。 儿童劫 正在吃。 儿童劫 吃了《12》个。 瑞萌萌 正在吃。 瑞萌萌 吃了《8》个。 """
二、异步调用与回调函数
异步调用:提交完任务后,不在原地等待任务执行完毕。
回调函数:可以为进程池或线程池内的每个进程或线程绑定一个函数,该函数在进程或线程的任务执行完毕后自动触发,并接收任务的返回值当作参数,该函数称为回调函数。
# 2,异步调用:提交完任务后,不在原地等待任务执行完毕, from concurrent.futures import ThreadPoolExecutor import time,random def eat(name): print("%s 正在吃。" % name) time.sleep(random.randint(3,5)) # 吃的时间 res = random.randint(7,13) # 吃几个 return {"name":name,"res":res} # weight({"name":name,"res":res}) # 这样写的话,相当于把两个函数写到一起了,耦合了,而我们是要解耦合的 def count(hamburger): hamburger = hamburger.result() # 这里的hamburger拿到的是一个对象 name = hamburger["name"] num = hamburger["res"] print("%s 吃了《%s》个." % (name,num)) if __name__ == '__main__': pool = ThreadPoolExecutor(3) # 参赛人数,用线程池 # 回调函数是在,前面的函数执行完,有返回值了,自动触发这个功能,把前面的对象直接当参数传给weight pool.submit(eat,"托儿所").add_done_callback(count) # 前面是对象,后面的是回调函数 pool.submit(eat,"儿童劫").add_done_callback(count) pool.submit(eat,"瑞萌萌").add_done_callback(count) # count拿到的是一个future对象obj,需要用obj.result()拿到结果,也就是 hamburger.result() """ 托儿所 正在吃。 儿童劫 正在吃。 瑞萌萌 正在吃。 瑞萌萌 吃了《12》个. 托儿所 吃了《12》个. 儿童劫 吃了《11》个. """
三、练习
在程序当中模拟浏览器的行为
from concurrent.futures import ThreadPoolExecutor import requests # 在程序当中模拟浏览器的行为,要用到这个模块 import time def get(url): print("GET %s." % url) # requests.get 实际上就是去目标站,下载一个文件到本地 response = requests.get(url) # 传上你的额 url地址,它会拿到一个对象 time.sleep(3) return {"url":url,"content":response.text} # text这个属性得到的是网页内容 def parse(res): """解析网页信息""" # 正则表达式,解析出你想要的内容 # 爬虫项目基本原理:先把内容(字符串)下载下来,再对内容进行处理得到自己想要的部分。 res = res.result() print("%s parse res is %s." % (res["url"],len(res["content"]))) if __name__ == '__main__': urls = [ "https://www.cnblogs.com/zoling7", "https://www.baidu.com", "https://www.huya.com", ] pool = ThreadPoolExecutor(2) for url in urls: pool.submit(get,url).add_done_callback(parse) """ GET https://www.cnblogs.com/zoling7. GET https://www.baidu.com. https://www.baidu.com parse res is 2443. GET https://www.huya.com. https://www.cnblogs.com/zoling7 parse res is 15181. https://www.huya.com parse res is 397258. """