用python帮助你从此快起来!

在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 的返回值

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


原文发布于微信公众号 - 猿媛牧场(xpchuiit)

原文发表时间:2018-06-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏小樱的经验随笔

【批处理学习笔记】第十六课:语句结构(2)

for语句(循环结构)     for语句可以实现类似于C语言里面的循环结构,当然for语句的功能要更强大一点,通过不同的开关可以实现更多的功能。for语句有多...

3064
来自专栏JavaEE

jsp技术前言:一、简介:二、hello world:三、jsp语法:四、九大内置对象:总结:

我是一名Java后台学习者,但是后台程序员也需要掌握一定的前端技术。虽然说现在前端基本上是react、vue、angular三分天下,但是作为一名Java程序员...

1273
来自专栏有趣的Python

6- vue django restful framework 打造生鲜超市 -完成商品列表页(下)

Vue+Django REST framework实战 搭建一个前后端分离的生鲜超市网站 Django rtf 完成 商品列表页下 drf中的reque...

34412
来自专栏程序员的知识天地

Python使用os模块、Try语句、pathlib模块判断文件是否存在

通常在读写文件之前,需要判断文件或目录是否存在,不然某些处理方法可能会使程序出错。所以最好在做任何操作之前,先判断文件是否存在。

1152
来自专栏大内老A

ASP.NET Core管道深度剖析(4):管道是如何建立起来的?

在《管道是如何处理HTTP请求的?》中,我们对ASP.NET Core的请求处理管道的构成以及它对请求的处理流程进行了详细介绍,接下来我们需要了解的是这样一个管...

1866
来自专栏IMWeb前端团队

hapi vs. express [1] —— 路由

hapi vs. express [1] —— 路由 前言 express 与 hapi 是两个基于 nodejs 的 web server 开发框架,它们由于...

2005
来自专栏抠抠空间

django之urls系统

Django的urls系统简介 Django 1.11版本 URLConf官方文档:https://docs.djangoproject.com/en/1.11...

2827
来自专栏自动化测试实战

flask第七篇——URL与视图函数的映射

2865
来自专栏博岩Java大讲堂

Java虚拟机--类加载器如何加载一个Class文件

1445
来自专栏前端大白专栏

angular使用管道实现搜索功能

3226

扫码关注云+社区