什么是Asyncio

  多线程有诸多优点且应用广泛,但也存在一定的局限性: 比如,多线程运行过程容易被打断,因此有可能出现 race condition 的情况;再如,线程切换本身存在一定的损耗,线程数不能无限增加,因此,如果I/O 操作非常 heavy,多线程很有可能满足不了高效率、高质量的需求。
  因此,Asyncio 应运而生。

Sync(同步) VS Async(异步)

  所谓 Sync,是指操作一个接一个地执行,下一个操作必须等上一个操作完成后才能执行。而 Async 是指不同操作间可以相互交替执行,如果其中的某个操作被 block 了,程序并不会等待,而是会找出可执行的操作继续执行。

Asyncio 工作原理

  Asyncio 和其他 Python 程序一样,是单线程的,它只有一个主线程,但是可以进行多个不同的任务(task),这里的任务,就是特殊的 future 对象。这些不同的任务,被一个叫做 event loop 的对象所控制。event loop 会根据其是否完成,把任务放到预备或等待状态的列表,然后遍历等待状态列表的任务,查看他们是否完成。如果完成,则将其放到预备状态的列表; 如果未完成,则继续放在等待状态的列表。

Asyncio 用法

import asyncio
import aiohttp
import time async def download_one(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
print('Read {} from {}'.format(resp.content_length, url))
#text_len = await resp.text()
#print('Read {} from {}'.format(len(text_len), url))
#print('len(text_len)',len(text_len)) async def download_all(sites):
tasks = [asyncio.create_task(download_one(site)) for site in sites]
await asyncio.gather(*tasks) def main():
sites = [
'https://www.baidu.com/',
'https://pypi.org/',
'https://www.sina.com.cn/',
'https://www.163.com/',
'https://news.qq.com/',
'http://www.ifeng.com/',
'http://www.ce.cn/',
'https://news.baidu.com/',
'http://www.people.com.cn/',
'http://www.ce.cn/',
'https://news.163.com/',
'http://news.sohu.com/'
]
start_time = time.perf_counter()
asyncio.run(download_all(sites))
end_time = time.perf_counter()
print('Download {} sites in {} seconds'.format(len(sites), end_time - start_time)) if __name__ == '__main__':
main() # 输出
Read 227 from https://www.baidu.com/
Read None from http://www.ce.cn/
Read None from http://www.ce.cn/
Read 38914 from http://www.people.com.cn/
Read None from https://news.qq.com/
Read None from https://news.163.com/
Read None from https://www.163.com/
Read 129268 from https://www.sina.com.cn/
Read None from http://www.ifeng.com/
Read None from https://news.baidu.com/
Read None from http://news.sohu.com/
Read 4293 from https://pypi.org/
Download 12 sites in 0.7875643999999999 seconds
  主函数里的 asyncio.run(coro) 是 Asyncio 的 root call,表示拿到 event loop,运行输入的 coro,直到它结束,最后关闭这个 event loop。
  事实上,asyncio.run() 是 Python3.7+ 才引入的,相当于老版本的以下语句:
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(coro)
finally:
loop.close()

Asyncio 有缺陷吗?

  首先有兼容性问题,如asyncio 与 requests库不兼容,因此上例使用的是aiohttp库(上例aiohttp库出现content_length为None,暂不知原因).另外是任务调度的问题,你需要 await 一系列的操作,就得使用 asyncio.gather();如果只是单个的 future,或许只用 asyncio.wait() 就可以了。那么,对于你的 future,你是想要让它 run_until_complete() 还是 run_forever() 呢?

Asyncio 还是 多线程?

  可以遵循以下伪代码的规范:

if io_bound:
if io_slow:
print('Use Asyncio')
else:
print('Use multi-threading')
else if cpu_bound:
print('Use multi-processing')
  • 如果是 I/O bound,并且 I/O 操作很慢,需要很多任务 / 线程协同实现,那么使用 Asyncio 更合适。
  • 如果是 I/O bound,但是 I/O 操作很快,只需要有限数量的任务 / 线程,那么使用多线程就可以了。
  • 如果是 CPU bound,则需要使用多进程来提高程序运行效率。

参考

  极客时间《Python核心技术与实战》专栏

 

Python进阶:并发编程之Asyncio的更多相关文章

  1. Python进阶:并发编程之Futures

    区分并发和并行 并发(Concurrency). 由于Python 的解释器并不是线程安全的,为了解决由此带来的 race condition 等问题,Python 便引入了全局解释器锁,也就是同一时 ...

  2. python并发编程之asyncio协程(三)

    协程实现了在单线程下的并发,每个协程共享线程的几乎所有的资源,除了协程自己私有的上下文栈:协程的切换属于程序级别的切换,对于操作系统来说是无感知的,因此切换速度更快.开销更小.效率更高,在有多IO操作 ...

  3. Python核心技术与实战——十八|Python并发编程之Asyncio

    我们在上一章学习了Python并发编程的一种实现方法——多线程.今天,我们趁热打铁,看看Python并发编程的另一种实现方式——Asyncio.和前面协程的那章不太一样,这节课我们更加注重原理的理解. ...

  4. python基础-并发编程之I/O模型基础

    1. I/O模型介绍 1.1 I/O模型基础 更好的理解I/O模型,需要先回顾:同步.异步.阻塞.非阻塞 同步:执行完代码后,原地等待,直至出现结果 异步:执行完代码后,不等待,继续执行其他事务(常与 ...

  5. Python 之并发编程之manager与进程池pool

    一.manager 常用的数据类型:dict list 能够实现进程之间的数据共享 进程之间如果同时修改一个数据,会导致数据冲突,因为并发的特征,导致数据更新不同步. def work(dic, lo ...

  6. python并发编程之Queue线程、进程、协程通信(五)

    单线程.多线程之间.进程之间.协程之间很多时候需要协同完成工作,这个时候它们需要进行通讯.或者说为了解耦,普遍采用Queue,生产消费模式. 系列文章 python并发编程之threading线程(一 ...

  7. python并发编程之gevent协程(四)

    协程的含义就不再提,在py2和py3的早期版本中,python协程的主流实现方法是使用gevent模块.由于协程对于操作系统是无感知的,所以其切换需要程序员自己去完成. 系列文章 python并发编程 ...

  8. python并发编程之multiprocessing进程(二)

    python的multiprocessing模块是用来创建多进程的,下面对multiprocessing总结一下使用记录. 系列文章 python并发编程之threading线程(一) python并 ...

  9. python并发编程之threading线程(一)

    进程是系统进行资源分配最小单元,线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.进程在执行过程中拥有独立的内存单元,而多个线程共享内存等资源. 系列文章 py ...

随机推荐

  1. vmvare ESXi使用

    新建主机,选择系统,自定义配置,选择ios镜像,完成,打开电源,开启配置

  2. 因子分解机 FM

    特征组合 人工方式的特征工程,通常有两个问题: 特征爆炸 大量重要的特征组合都隐藏在数据中,无法被专家识别和设计 针对上述两个问题,广度模型和深度模型提供了不同的解决思路. 广度模型包括FM/FFM等 ...

  3. 复旦高等代数I(19级)每周一题

    本学期的高等代数每周一题活动计划从第2教学周开始,到第15教学周结束,每周的周末公布一道思考题(共14道,思考题一般与下周授课内容密切相关),供大家思考和解答.每周一题将通过“高等代数官方博客”(以博 ...

  4. R语言中查询帮助

    可以尝试下面的几种方式 help(lapply,package=,....)?lapply??lapplyhelp.search('lapply')apropos('norm') #函数名记不全时用? ...

  5. java基础之 final

    参考文档: 内存模型&final:http://www.infoq.com/cn/articles/java-memory-model-6/   根据程序上下文环境,Java关键字final有 ...

  6. java读取文件夹下文件及txt内容

    public class PositionController {     // 读取txt内容     public static String txt2String(File file) {    ...

  7. 《微信小程序商城开发实战》唐磊,全网真实评价截图,不吹不黑,全部来自网友的真实评价

    偶尔看了下网友的销量和评价,感觉还不错,因为市面上大多关于小程序的书籍可能写的不够全面,要么只是点到为止的大致罗列,要么就是只简单介绍一下小程序的 界面设计这块.这样很难给学习小程序开发的人一个完成的 ...

  8. Pushing state-of-the-art in 3D content understanding

    Pushing state-of-the-art in 3D content understanding 2019-10-31 06:34:08 This blog is copied from: h ...

  9. JVM探究之 —— 类加载过程

    1. 类加载是什么 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 与那些在编译时需要进行连 ...

  10. SyntaxError: expected expression, got ")" void() : 1: 5

    这个错误的意思是: 本来希望得到 一个 表达式, 缺得到了 ), 凡是 这样的错误, 就是 函数 在当前位置, 需要一个参数! 参数没有给, 就 输入 ) 右括号了! 错误位置 1: 5, 就是 指 ...