python并发编程笔记5

python并发编程笔记5

是根据蚂蚁学Python的视频做的笔记,方便自己后续回顾

视频链接:BV1bK411A7tV

老师的源码

这一份笔记对应的是视频的P7-P8

P7-Python好用的线程池ThreadPoolExecutor

1、线程池的原理

1.1、线程的生命周期

新建线程系统需要分配资源、终止线程系统需要回收资源

如果可以重用线程,则可以减去新建/终止的开销

在这里插入图片描述

1.2、线程池是怎么流转的呢

由两部分组成

线程池:里面是提前预先建好的线程,线程会被重复使用

任务队列:新的任务而不是直接创建线程

线程池会将任务队列的任务挨个取出依次执行,任务执行完后会取下一个任务执行,若没有任务,则回到线程池,不会进行销毁

在这里插入图片描述

2、使用线程池的好处

2.1、提升性能:

因为减去了大量新建、终止线程的开销,重用了线程资源;

2.2、适用场景:

适合处理突发性大量请求或需要大量线程完成任务、但实际任务处理时间较短

2.3、防御功能:

能有效避免系统因为创建线程过多,而导致系统负荷过大相应变慢等问题

2.4、代码优势:

使用线程池的语法比自己新建线程执行线程更加简洁

3、ThreadPoolExecutor的使用语法

前提:导入对应模块

from concurrent.futures import ThreadPoolExecutor,as_completed

用法1:map函数

很简单,注意map结果和入参是顺序对立的(指results 与 urls的顺序是一一对应的)

pool.map(函数,列表)会自动创建和列表等数量(不确定)的线程来处理。

with ThreadPoolExecutor() as pool:
    
    # 传入一个函数名(craw),和参数列表(urls)
    results = pool.map(craw, urls)
    
    for result in results:
        print(result)

用法2:future模式

更强大,注意如果用as——completed顺序是不定的

with ThreadPoolExecutor() as pool:
    
    # 传入的是单个url,而不是urls,返回的是一个future对象,放进一个futures里面
    futures = [ pool.submit(craw, url)
                for url in urls ]
    
    # 结果两种遍历方式
    # 会根据urls的对应顺序挨个获取future,并且获取结果
    for future in futures:
        print(future.result())
    
    # as_completed方式,好处:哪个任务先执行完了就先返回
    for future in as_completed(futures):
        print(future.result())

4、使用线程池改造爬虫程序

注意事项:

视频作者的代码讲的比较快,一些基础我这里普及一下

代码中使用的

zip方法是将urls与对应的的htmls新包为一个元组。

fufturs字典也是为存储跟上述相似的对应关系。

zip实例:

url_list = [1, 2, 3, 4]
html_list = ["a", "b", "c", "d"]
html_list = list(zip(url_list, html_list))
print(html_list)
for url, html in html_list:
    print(url, len(html))

结果:

[(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')]
1 1
2 1
3 1
4 1

代码:

import concurrent.futures
import blog_spider

# craw,使用map方法调用线程池
with concurrent.futures.ThreadPoolExecutor() as pool:
    htmls = pool.map(blog_spider.craw, blog_spider.urls)
    htmls = list(zip(blog_spider.urls, htmls))
    for url, html in htmls:
        print(url, len(html))

print("craw over")

# parse 使用future模式调用线程池

with concurrent.futures.ThreadPoolExecutor() as pool:
    futures = {}
    for url, html in htmls:
        future = pool.submit(blog_spider.parse, html)
        # 加入到字典的是好处url与future有对应关系
        futures[future] = url

    # 得到结果 有序的,等所有任务执行完了再返回
    # for future, url in futures.items():
    #     print(url, future.result())

    # as_completed方式,好处:哪个任务先执行完了就先返回,相比上面这个是无序的
    for future in concurrent.futures.as_completed(futures):
        url = futures[future]
        print(url, future.result())


总结:

使用这种map或者future模式比02中使用for循环实现thread好用的多

P8-Python使用线程池在Web服务中实现加速

1、Web服务的架构以及特点

Web后台服务的特点:

1、Web服务对响应时间要求非常高,比如要求200MS返回

2、Web服务有大量的依赖IO操作的调用,比如磁盘文件、数据库、远程API(暗示使用线程池来加速)

3、Web服务经常需要处理几万人、几百万人的同时请求(不能无限的创建线程池子)

在这里插入图片描述

2、使用线程池ThreadPoolExecutor加速

使用线程池ThreadPoolExecutor的好处:

1、方便的将磁盘文件、数据库、远程API的IO调用并发执行

2、线程池的线程数目不会无限创建(导致系统挂掉),具有防御功能

3、代码用Flask实现Web服务并实现加速

import flask
import json
import time
from concurrent.futures import ThreadPoolExecutor

app = flask.Flask(__name__)
pool = ThreadPoolExecutor()

def read_file():
    time.sleep(0.1)
    return "file result"


def read_db():
    time.sleep(0.2)
    return "db result"


def read_api():
    time.sleep(0.3)
    return "api result"


# @app.route("/")
# def index():
#     result_file = read_file()
#     result_db = read_db()
#     result_api = read_api()
#
#     return json.dumps({
#         "result_file": result_file,
#         "result_db": result_db,
#         "result_api": result_api,
#     })

@app.route("/")
def index():
    result_file = pool.submit(read_file)
    result_db = pool.submit(read_db)
    result_api = pool.submit(read_api)

    return json.dumps({
        "result_file": result_file.result(),
        "result_db": result_db.result(),
        "result_api": result_api.result(),
    })



if __name__ == '__main__':
    app.run()

总结:

通过线程池加速Web服务

全局中创建一个pool对象,用submit获取file对象,用result获取结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值