前言
最近对几种并发的方式进行了很多探索。之前一直采用多线程、多进程来提高单个程序的并发数。但是这两种方式各有各的不足之处,在进行频繁的I/O操作的时候,多进程模式的效率并不是很理想,而多线程消耗了很多系统资源,如果处理不当还会出现内存泄漏的情况。于是了解到了Python的标准库中的 asyncio ,采用协程的方式异步调用函数。
asyncio介绍
关于协程的中文文档非常之少,于是基本上我的所有探索都是基于官方的Documentation来的。
asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。
asyncio的编程模型就是一个消息循环。我们从asyncio模块中直接获取一个EventLoop的引用,然后把需要执行的协程扔到EventLoop中执行,就实现了异步IO。
asyncio的基础用法
下面用我写的一个例子来说明基本的用法:
import asyncio async def test(i): me = str(i) print("I am Test --" + me) await asyncio.sleep(1) # 用来模拟进行一些任务 print("Task Over! --" + me) if __name__ == '__main__': loop = asyncio.get_event_loop() tasks = asyncio.wait([test(i) for i in range(3)]) print("Start Tasks") loop.run_until_complete(tasks) print("Main process over")
这个程序将会得到的结果是:
Start Tasks at 2020-02-09 17:00:00 I am Test --2--at 2020-02-09 17:00:00 I am Test --1--at 2020-02-09 17:00:00 I am Test --0--at 2020-02-09 17:00:00 Task Over! --2-at 2020-02-09 17:00:01 Task Over! --1-at 2020-02-09 17:00:01 Task Over! --0-at 2020-02-09 17:00:01 Main process over at 2020-02-09 17:00:01
显然,三个coroutine都是并发进行的,并没有等待三个三秒的时间,都是在一秒内同时完成了任务
asyncio + aiohttp
关于协程的一个最佳用途莫非是并发的进行HTTP请求了,这在编写爬虫程序的时候有着极佳的性能。
而你需要知道的是,不要在协程中使用 requests库 ,因为requests库是IO阻塞的,和协程并不能很好的兼容。
所以这里就引入了asyncio的最佳搭档:aiohttp
aiohttp的基础用法
这里我同样写了一个简单的示例来让你快速的了解aiohttp的特性,不难看出的是,aiohttp和requests的用法是很相似的,只不过它对于协程的支持非常的好。
import asyncio import aiohttp async def sendHTTP(url): async with aiohttp.ClientSession() as ss: async with ss.get(url) as r: print("HTTP Status:" + str(r.status)) print(await r.text()) if __name__ == '__main__': loop = asyncio.get_event_loop() print("Start!") # 以获取Github的时间轴作为示例 loop.run_until_complete(sendHTTP("https://api.github.com/events")) print("Over!")
总结
以上就是Python3中的协程并发的基础用法,更多的介绍可以查阅一下相关的文档。
asyncio的Python官方Documentation:
https://docs.python.org/3.5/library/asyncio-task.html
aihttp Documentation:
https://docs.aiohttp.org/en/stable/
文章评论