龙空技术网

python并发编程(二)进程/线程/协程/信号量

零一间 136

前言:

而今同学们对“python 进程池阻塞和非阻塞”大体比较重视,看官们都想要了解一些“python 进程池阻塞和非阻塞”的相关资讯。那么小编同时在网摘上汇集了一些关于“python 进程池阻塞和非阻塞””的相关内容,希望兄弟们能喜欢,各位老铁们一起来学习一下吧!

在Web服务中使用线程池加速

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

Web后台服务的特点:

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

2、Web服务有大量的依赖IO操作的调用,比如磁盘文件、数据库、远程API

3、Web服务经常需要处理几万人、几百万人的同时请求

2、使用线程池ThreadPoolExecutor加速

使用线程池ThreadPoolExecutor的好处:

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

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

使用多进程multiprocessing加速程序的运行

1、有了多线程threading,为什么还要用多进程multiprocessing

如果遇到了CPU密集型计算,多线程反而会降低执行速度!

虽然有全局解释器锁GIL,但是因为有IO的存在多线程依然可以加速运行。

CPU密集型计算,线程的自动切换反而变成了负担,多线程甚至减慢了运行速度。

multiprocessing模块就是python为了解决GIL缺陷引入的一个模块,原理是用多进程在多CPU上并行执行。

2、多进程multiprocessing知识梳理(对比多线程threading)

3、代码实战:单线程、多线程、多进程对比CPU密集计算速度

CPU密集型计算:100次“判断大数字是否是素数”的计算

由于GIL的存在,多线程比单线程计算的还慢,而多进程可以明显加快执行速度

Python异步IO实现并发爬虫

单线程爬虫的执行路径

协程:在单线程内实现并发

用一个超级循环(其实就是while true)循环配合IO多路复用原理(IO时CPU可以干其他事情)

Python 异步IO库介绍:asyncio

import asyncio# 获取事件循环loop = asyncio.get_event_loop()# 定义协程async def myfunc(url):    await get_url(url)# 创建task列表tasks = [loop.create_task(myfunc(url)) for url in urls]# 执行爬虫事件列表loop.run_until_complete(asyncio.wait(tasks))

注意:

异步IO编程中,依赖的库必须支持异步IO特性。requests 不支持异步,需要用 aiohttp。

自动听歌、解压缩、下载等等

使用subprocess启动电脑的子进程

subprocess 模块:

允许你生成新的进程

连接它们的输入、输出、错误管道

并且获取它们的返回码

应用场景:

每天定时8:00自动打开酷狗音乐播放歌曲

调用7z.exe自动解压缩.7z文件

通过Python远程提交一个torrent种子文件,用电脑启动下载

subprocess的实例

用默认的应用程序打开歌曲文件# 注:windows下是start、mac下是open、Linux是see# windows 环境需要加 shell = Trueproc = subprocess.Popen(['start', '余生一个浪.mp3'], shell=True)proc.communicate()用7z.exe解压7z压缩文件proc = subprocess.Popen([r"C:\Program Files\7-Zip\7z.exe",                         "x", "./datas/7z_test.7z", "-o./datas/extract_7z_test", "-aoa"], shell=True)proc.communicate()

在异步IO中使用信号量控制爬虫并发度

信号量(英语:Semaphore)

信号量(英语:Semaphore)又称为信号量、旗语

是一个同步对象,用于保持在0至指定最大值之间的一个计数值。当线程完成一次对该semaphore对象的等待(wait)时,该计数值减一;当线程完成一次对semaphore对象的释放(release)时,计数值加一。当计数值为0,则线程等待该semaphore对象不再能成功直至该semaphore对象变成signaled状态semaphore对象的计数值大于0,为signaled状态;计数值等于0,为nonsignaled状态.

方式一:

sem = asyncio.Semaphore(10)# ... laterasync with sem:    # work with shared resource

方式二:

sem = asyncio.Semaphore(10)# ... laterawait sem.acquire()try:    # work with shared resourcefinally:    sem.release()
异步库Asyncio VS 异步库Gevent

asyncio:Python3 官方异步IO库

import asyncio# 获取事件循环loop = asyncio.get_event_loop()# 定义协程async def myfunc(url):    await get_url(url)# 创建task列表tasks = [loop.create_task(myfunc(url)) for url in urls]# 执行爬虫事件列表loop.run_until_complete(asyncio.wait(tasks))

注意:

asyncio 很多库都不支持

Gevent:Python 异步IO库

安装:

pip install gevent

Gevent是一个基于微线程库Greenlet的并发框架

原理:

提供猴子补丁MonkeyPatch方法,通过该方法gevent能够 修改标准库里面大部分的阻塞式系统调用,包括socket、ssl、threading和 select等模块,而变为协作式运行

异步库 asyncio 对比 gevent

Gevent:

优点:只需要monkey.patch_all(),就能自动修改阻塞为非阻塞,简单强大缺点:不知道它具体patch了哪些库修改了哪些模块、类、函数。 创造了“隐式的副作用”,如果出现问题很多时候极难调试

Asyncio:

优点:明确使用asyncio、await等关键字编程,直观易读缺点:只支持很少的异步库,比如aiohttp

总结自蚂蚁学Python笔记

标签: #python 进程池阻塞和非阻塞