(十)异步调用与回调机制

一、同步调用


提交任务有两种方式:同步调用,异步调用。

同步调用:提交完任务后,就在原地等待任务执行完毕,拿到结果再执行下一行代码,导致程序是串行执行。

例子:今年你们公司开年会,举办了一个吃汉堡大赛,然后把计算下大家一共吃了多少个,谁的最多,谁发的年终奖就最多。

# 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.
"""

 

 

 

 

 

 

posted @ 2020-07-29 15:36  zoling7  阅读(235)  评论(0编辑  收藏  举报