查看原文
其他

用python帮助你从此快起来!

上海小胖 Python专栏 2018-10-28




在python的网络模型中,为了实现高并发有很多方案:多线程多进程。无论多线程和多进程,IO的调度更多取决于系统,而协程的方式,调度来自用户

使用协程可以实现高效的并发任务。而这个操作就叫异步IO(asyncio)

简单来说:当我们发起一个 IO 操作,而不用等待指令集结束,就可以继续做其他事情,当它结束时,会得到相应的通知


Asyncio 并不能带来真正的并行(parallelism)。当然,因为 GIL(全局解释器锁)的存在,使用Cython作为Python解释器(最常见的解释器)的多线程也不能带来真正的并行。

交给 asyncio执行的任务,称为协程(coroutine)。一个协程可以放弃执行,把机会让给其它协程(即 yield from 或 await)。


初识asyncio

首先来认识一下Coroutine,我已经对每段代码都加上了注释

import asyncio

# asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。
async def coroutine():
   print('in coroutine')

# asyncio的编程模型就是一个消息循环
# 从asyncio模块中直接获取一个EventLoop的引用
event_loop = asyncio.get_event_loop()
try:
   print('starting coroutine')
   coro = coroutine()
   print('entering event loop')
   # 把需要执行的协程,这里也就是coroutine扔到EventLoop中执行
   event_loop.run_until_complete(coro)
finally:
   print('closing event loop')
   event_loop.close()
结果如图:

首先是获取一个事件循环 asyncio.get_event_loop(),然后用 run_until_complete 执行 coroutine 对象,当 coroutine 执行完成并退出时, run_until_complete 也会随后退出。

获取Coroutine返回值
在刚刚,我们已经可以有效的使用 run_until_complete 函数来执行asyncio了,现在我们需要多做一步的就是获取异步请求的返回值。
run_until_complete 会把 Coroutine 的返回值当做自身的返回值返回给调用方
import asyncio

async def coroutine():
   print('in coroutine')
   # 增加了一个返回值
   return 'result'

event_loop = asyncio.get_event_loop()
try:
   # 有了之前的基础,我们这里就不再单独获取coroutine的对象了
   # run_until_complete会返回coroutine的返回值
   return_value = event_loop.run_until_complete(coroutine())
   print(f'it returned: {return_value}')
finally:
   event_loop.close()
结果如图:


链式调用
之前的操作都是调用某个单一函数,但在工作中,往往会有函数调用函数的情况,一起来看下
import asyncio

# 函数1
async def one():
   print('in one')
   asyncio.sleep(1)
   print('one end')
   return 'one'

# 函数2
async def two(arg):
   print('in two')
   asyncio.sleep(1)
   print('two end')
   return 'two with arg {}'.format(arg)

# 将作为coroutine
async def outer():
   print('in outer')
   print('waiting for one')
   # 等待函数1的返回值
   result1 = await one()
   print('waiting for two')
   # 等待函数2的返回值
   result2 = await two(result1)
   # 将2个结果一并返回
   return result1, result2

event_loop = asyncio.get_event_loop()
try:
   return_value = event_loop.run_until_complete(outer())
   print(f'result value: {return_value}')
finally:
   event_loop.close()
这里使用了 asyncio.sleep而不是time.sleep为的就是模拟异步的任务请求
使用 await 可以针对耗时的操作进行挂起,就像生成器里的 yield 一样,使函数让出控制权。
协程遇到 await ,事件循环将会挂起该协程,执行别的协程,直到其他的协程也挂起或者执行完毕,再进行下一个协程的执行
一起来看下结果:

时间上确实节省了很多,这就是异步的强大!
好了,今天的内容就到这里结束了,一起来回顾下:
  • python通过 asyncio 来实现异步请求

  • 在python3.5开始,使用关键字 async 来定义 coroutine 实体函数

  • 使用关键字 await 来等待 coroutine 的返回值

如果你对今天的内容还感兴趣的话,何不点个赞再走呢?
如果感兴趣到想赞赏我,就不要犹豫啦~




目前我开了2个主群,我邀请了一些我的BAT伙伴前来助阵。定期也会在群里组织抽奖、送书等活动。更有各种资源分享。

目前2个主群都以过百,想要加入的小伙伴,可以加我微信,我拉你们,或者公众号回复关键“关注作者”。


另外高级群」已经升级啦!如果你错过了种子轮,难道还要错过天使轮吗?群内不定期组织红包接龙,每天中午1小时的随即话题讨论没有广告只聊技术生活,这样的群上哪找?

推荐阅读:
如何通过一些骚操作有效的控制Python类
用Python给程序加个进度条

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存