python 进阶第五关 进阶任务_python进阶(五、并发编程:池、协程)

2.并发编程

2.6 池:concurrent.futures模块

2.6.1 简介

池:预先的开启固定个数的进程数/线程数,当任务来临的时候,直接提交给已经开好的进程/线程,让这个进程/线程去执行就可以了。

池节省了进程、线程的开启、关闭、切换需要的时间,并且减轻了操作系统调度的负担。

当有新的请求提交到进程池中时,如果池未满,则会分配一个进程用来执行该请求;反之,如果池中的进程数已经达到规定最大值,那么该请求就会等待,只要池中有进程空闲下来,该请求就能得到执行。

池缺点:一个池中的任务个数限制了我们程序的并发个数

concurrent.futures模块提供了高度封装的异步调用接口

ThreadPoolExecutor:线程池,提供异步调用

ProcessPoolExecutor: 进程池,提供异步调用

concurrent.futures模块出现过程:

(1)threading模块没有提供池

(2)multiprocessing模块仿照threading编写,并增加了Pool功能

(3)concurrent.futures模块出现,包含了线程池和进程池,两者使用方法相似

通常进程池中进程的数量= CPU核数+1(一般大于CPU核心数,小于CPU核数2)

进程池适用于高计算场景(没有I/O操作:没有文件操作,没有数据库操作、没有网络操作、没有input),这种场景很少。

通常线程池中线程的数量= CPU核数5(一般根据I/O比例定制,推荐CPU核数*5)

线程池和进程池的用法基本相同,下面代码会用线程池或进程池编写

2.6.2 submit()启用线程(进程)池:

(1)创建线程池:实例化

(2)将任务放入线程

使用线程池,打印当前线程id:

7342d3ec3513b701cc02ef25ef8067c9.png

6bdc8b575b4be5c644a75631698ae4ea.png

增加时延占用线程

3474168cf43b929edb9c539f5377e248.png

6ab9f73626749542a8eb087a25152ca7.png

传参:

71b313f54b467e5bc356d8c977219388.png

953189f55970c56be3476721916d944d.png

启用进程池:进程池的用法和线程池用法基本相同

9a93b49cd0c0f632956a66cc273e949f.png

0bc18a5a5e3ca48ae9adf1b9790e1006.png

2.6.3 result()获取任务结果

使用ret.result()获取返回结果,程序会同步阻塞,不再并发运行

3d35799ef2bddb6f31887e0b350666d4.png

7e789ed3b632be7567f7116568aefbcc.png

使用列表接收返回对象,最后统一打印。程序恢复并发

d2fdbdf116d13807d2684a658ad3bd74.png

aa8e594d1f0d15e220481e4a46dc1d34.png

也可以使用字典存储返回对象

e49b84370a91b9426ede84c3a7061b16.png

b8de759092d8e01aae523ca4932eb857.png

2.6.4 map()取代for循环和submit的操作

b87b54d48c72b89b5f5b356ab5ab67cb.png

b1167eb4c1f4a017d6de2987256f82ac.png

传多个参数

8c7311eb217c0141de81fa16e3f1742f.png

989f58dba4ad41cbe2eb9794d47b2728.png

可迭代对象使用列表

6a798b0dedef6b755fa006f8c7350f7f.png

815216966d3f9783295ef043253c6476.png

线程map

98644f7f76b58161dafa4cbdc43bc060.png

c03284a1cd1fd8bcd19bb717035e55cd.png

2.6.5 add_done_callback()回调函数

谁先执行完,先处理谁。处理速度最快,效率最高。但数据的顺序是混乱的

7d97f6cc0d312a634bfa4ba81e53ecba.png

accd295baaab9681520e095dfbebdb3a.png

想要识别任务和结果的对应关系,可以给结果增加标识组成元组

322ce32b3ac7506b2a6a1efb857b4bb4.png

9b1666629d1fdea1a33b3dcc7d72a989.png

实例:分析网页信息

ba2c52407e69b24d41d1208a46cc0bab.png

ef3b3149ceccdf13d1f1a5c0beca895e.png

执行结果:

1dc7b98ba2c2cb20596fc8627d26469e.png

3b5e45f9869cb094e3da31f43c6fe29a.png

2.7 协程

2.7.1 协程概念(重要)

对于单线程下,我们不可避免程序中出现io操作,但如果我们能在自己的程序中(即用户程序级别,而非操作系统级别)控制单线程下的多个任务能在一个任务遇到io阻塞时就切换到另外一个任务去计算,这样就保证了该线程能够最大限度地处于就绪态,即随时都可以被cpu执行的状态,相当于我们在用户程序级别将自己的io操作最大限度地隐藏起来,从而可以迷惑操作系统,让其看到:该线程好像是一直在计算,io比较少,从而更多的将cpu的执行权限分配给我们的线程。

1)协程是操作系统不可见的

协程的本质就是在单线程下,由用户自己控制一个任务遇到io阻塞了就切换另外一个任务去执行,以此来提升效率。

协程的所有切换都基于用户,只有在用户级别能够感知到的IO才能用协程模块做切换来规避(例如:socket、请求网页的操作)。

一些和文件相关的IO操作,只有操作系统能够感知到,只能使用线程来规避

2)协程的优点:

减轻了操作系统的负担

造成线程很忙的现象,可以得到更多的cpu的执行权限(时间片)

3)进程、线程、协程的区别:

进程:数据隔离 数据不安全 操作系统级别 开销非常大 可以利用多核

线程:数据共享 数据不安全 操作系统级别 开销非常小 不能利用多核 对IO更敏感

协程:数据共享 数据安全(单线程) 用户级别 开销最小 不能利用多核 不能识别文件操作IO

4)实现协程的2个模块:

gevent模块和asyncio模块

2.7.2 gevent第三方模块(重要)

Gevent是一个第三方库。

gevent模块利用了greenlet底层模块来完成切换,加上自己的规避I/O功能

1)协程实现

66a4d3e1d4138c7f9a2147848a129209.png

主程序中添加IO,可以调用协程。但主程序IO中断时间较短,协程程序无法运行完成

e4d9b13d820678d92547676614b8523d.png

增加IO时长或增加IO次数,可以使协程完成运行。

64f01d2f2dca235cbfcd254227a4282e.png

推荐:创建阻塞,直到协程执行完成

565d345ca8df61e6a8b0116bca8e906c.png

2)协程并发

da12ea30d63a9d4bfb98d782a0d2547f.png

阻塞多个指定的协程

9267d898d851d8e768c5de15d787a806.png

2.7.3 猴子补丁

使用time.sleep()会影响协程的并发,同样socket、requests等模块执行时,都会遇到该问题。

e9cd3e357d78de6593604f3a1f627893.png

1)解决time、socket、requests等模块不能并发问题:

在time模块之前导入monkey,并执行“monkey.patch_all()”

169db30fee442836efa9d0063ddfcca5.png

2)判断猴子补丁是否有效

ec7e5807c9ac8d27c0afd6b2c64d85bf.png

源码中值为True的默认支持,没有列出来的不支持

0b3a21536c1df4d103812462229fbf2e.png

总结:将IO操作写到函数里,然后将函数提交gevent。在需要使用函数结果的地方使用join()制造阻塞。

3)基于gevent协程和线程池,实现socket并发

d2adb543b49450f0e76965215ccfab0d.png

4)4核cpu能处理的并发数:

进程数:5

线程:20

协程:500

最大并发数 = 5 * 20 * 500 = 5W,已经足够使用。

2.7.4asyncio 内置模块

asyncio模块是python原生的内置模块

asyncio模块利用了yield底层模块来完成切换,加上自己的规避I/O功能

两个关键字:

async(重要)

await(重要)

1)功能实现

da1977dfeb60c57046572d6a71837c04.png

2)实现并发

0b1a3b74b569046c684ba2cb8a4bcf69.png

3)asyncio使用协程完成http访问

d18645aa2c00cfecf0e333b7cca09864.png

962eef35afad54d1710c6f717cb22367.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值