开发者社区> 天飞> 正文

Python协程:从yield/send到async/await

简介: 这个文章理好了脉落。 http://python.jobbole.com/86069/ 我练 习了一番,感受好了很多。。。 Python由于众所周知的GIL的原因,导致其线程无法发挥多核的并行计算能力(当然,后来有了multiprocessing,可以实现多进程并行),显得比较鸡肋。
+关注继续查看

这个文章理好了脉落。

http://python.jobbole.com/86069/

我练 习了一番,感受好了很多。。。

Python由于众所周知的GIL的原因,导致其线程无法发挥多核的并行计算能力(当然,后来有了multiprocessing,可以实现多进程并行),显得比较鸡肋。既然在GIL之下,同一时刻只能有一个线程在运行,那么对于CPU密集的程序来说,线程之间的切换开销就成了拖累,而以I/O为瓶颈的程序正是协程所擅长的:

多任务并发(非并行),每个任务在合适的时候挂起(发起I/O)和恢复(I/O结束)

弄清楚了asyncio.coroutine和yield from之后,在Python3.5中引入的async和await就不难理解了:可以将他们理解成asyncio.coroutine/yield from的完美替身。当然,从Python设计的角度来说,async/await让协程表面上独立于生成器而存在,将细节都隐藏于asyncio模块之下,语法更清晰明了。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import asyncio
import time
import random

'''
def old_fib(n):
    res = [0] * n
    index = 0
    a = 0
    b = 1
    while index < n:
        res[index] = b
        a, b = b, a + b
        index += 1
    return res

print("-"*10 + "test old fib " + "-"*10)
for fib_res in old_fib(20):
    print(fib_res)

def fib(n):
    index = 0
    a = 0
    b = 1
    while index < n:
        yield b
        a, b = b, a + b
        index += 1

print("-"*10 + "test yield fib " + "-"*10)
for fib_res in fib(20):
    print(fib_res)

def stupid_fib(n):
    index = 0
    a = 0
    b = 1
    while index < n:
        sleep_cnt = yield b
        print("let me think {0} secs".format(sleep_cnt))
        time.sleep(sleep_cnt)
        a, b = b, a + b
        index += 1
print("-"*10 + "test yield send " + "-"*10)
N = 20
sfib = stupid_fib(N)
fib_res = next(sfib)
while True:
    print(fib_res)
    try:
        fib_res = sfib.send(random.uniform(0, 0.5))
    except StopIteration:
        break

def copy_fib(n):
    print("I am copy from fib")
    yield from fib(n)
    print("copy end")
print("-"*10 + "test yield from " + "-"*10)
for fib_res in copy_fib(20):
    print(fib_res)

def copy_stupid_fib(n):
    print("I am copy from stupid fib")
    yield from stupid_fib(n)
    print("Copy end")

print("-"*10 + "test yield from and send" + "-"*10)
N = 20
csfib = copy_stupid_fib(N)
fib_res = next(csfib)
while True:
    print(fib_res)
    try:
        fib_res = csfib.send(random.uniform(0, 0.5))
    except StopIteration:
        break


@asyncio.coroutine
def smart_fib(n):
    index = 0
    a = 0
    b = 1
    while index < n:
        sleep_secs = random.uniform(0, 0.2)
        yield from asyncio.sleep(sleep_secs)
        print("Smart one think {} secs to get {}".format(sleep_secs, b))
        a, b = b, a + b
        index += 1

@asyncio.coroutine
def stupid_fib(n):
    index = 0
    a = 0
    b = 1
    while index < n:
        sleep_secs = random.uniform(0, 0.4)
        yield from asyncio.sleep(sleep_secs)
        print("Stupid one think {} secs to get {}".format(sleep_secs, b))
        a, b = b, a + b
        index += 1

loop = asyncio.get_event_loop()
tasks = [
    asyncio.async(smart_fib(10)),
    asyncio.async(stupid_fib(10)),
    ]
loop.run_until_complete(async.wait(tasks))
print("All fib finished.")
loop.close()
        
'''
    
async def smart_fib(n):
    index = 0
    a = 0
    b = 1
    while index < n:
        sleep_secs = random.uniform(0, 0.2)
        await asyncio.sleep(sleep_secs)
        print("Smart one think {} secs to get {}".format(sleep_secs, b))
        a, b = b, a + b
        index += 1

async def stupid_fib(n):
    index = 0
    a = 0
    b = 1
    while index < n:
        sleep_secs = random.uniform(0, 0.4)
        await asyncio.sleep(sleep_secs)
        print("Stupid one think {} secs to get {}".format(sleep_secs, b))
        a, b = b, a + b
        index += 1

loop = asyncio.get_event_loop()
tasks = [
    asyncio.async(smart_fib(10)),
    asyncio.async(stupid_fib(10)),
    ]
loop.run_until_complete(asyncio.wait(tasks))
print("All fib finished.")
loop.close()

Python中的协程经历了很长的一段发展历程。其大概经历了如下三个阶段:

  1. 最初的生成器变形yield/send
  2. 引入@asyncio.coroutine和yield from
  3. 在最近的Python3.5版本中引入async/await关键字

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
python yield 用法详解
python yield 用法详解
82 0
【Python基础之函数:异常相关和生成器对象、yield用法、生成器表达式】
【Python基础之函数:异常相关和生成器对象、yield用法、生成器表达式】
33 0
3_python高阶_协程—yield实现多任务
python高阶_协程—yield实现多任务
47 0
对于python中async与await的理解
对于python中async与await的理解
220 0
yield 关键字在 Python 中的用途是什么?
要了解其yield作用,必须了解什么是 生成器。而且,了解生成器之前,必须了解 _iterables_。
63 0
盘点一道Python中的yield生成器的题目
盘点一道Python中的yield生成器的题目
61 0
说说Python中yield的用法?
公众号新增加了一个栏目,就是每天给大家解答一道Python常见的面试题,反正每天不贪多,一天一题,正好合适,只希望这个面试栏目,给那些正在准备面试的同学,提供一点点帮助!
42 0
Python编程:协程async和await
Python编程:协程async和await
101 0
Python编程:生成器yield与yield from区别简单理解
Python编程:生成器yield与yield from区别简单理解
121 0
Python语言学习:复杂函数(yield/@property)使用方法、案例应用之详细攻略
Python语言学习:复杂函数(yield/@property)使用方法、案例应用之详细攻略
55 0
+关注
天飞
一个运维老同志
文章
问答
文章排行榜
最热
最新
相关电子书
更多
给运维工程师的Python实战课
立即下载
Python 脚本速查手册
立即下载
ACE 区域技术发展峰会:Flink Python Table API入门及实践
立即下载