彻底搞懂python协程-第一篇(关键词1-4)

任何复杂的概念或系统都不是凭空出现的,我们完全可以找到它的演化历程,寻根究底终会发现,其都是在一系列并不那么复杂的简单组件上发展演化而来!
by 落花僧

本文通过一系列关键概念,逐步递进理解协程。

0.并发

不管做什么事情,我们都不喜欢等待,能够越快越好。在web服务领域,说并发量,就是指一个web服务器能同一时间接收多少用户同时访问,在互联网早期因为用户量低,所以上古时候都使用多fork线程来应付同时访问的用户,但随着同一时间用户量的增加,线程的开销对服务器压力越来越大,所以出现了一些同一时间提供并发量的编程模型(思想),而协程就是其中一种。

1. iterator(迭代器)

在python中"序列"的对象都可用 iter(the_sequence_object)变成一个iterator:

>>>iter('this is string.' )
<str_iterator at 0x1033ce9e8>

>>>iter([1,2,3])
<list_iterator at 0x1033b3f60>

>>>iter(set({1,2,3}))
<set_iterator at 0x103434048>

>>>iter(1)
TypeError: 'int' object is not iterable

int不是序列对象,不能iter, 那么问题来了,能iter又有什么用呢?
看下面(例子1-1):

a = [1, 2, 3]
a_iterator = iter(a)
while True:
    try:
        print(next(a_iterator))
    except StopIteration:
        break

这段代码遍历了列表a, 其等同于(例子1-2):

a = [1, 2, 3]
for i in a:
     print(i)

在例子1-2的for循环前解释器隐式的调用了iter, 遍历循环中调用next. 目前看起来这个迭代器的作用就是将所有序列对象进行了抽象,可以统一使用next不断获取序列的下一个元素,在业务代码层次表现出来的是我们可以统一使用for in遍历操作。注意:这个序列对象不一定非得是有序的数组类型的数据结构。

2.Lazy evaluation(惰性计算)

简而言之就是用到的时候我们再去求值,比如可以写一个无限生成斐波那契数列的函数,想要多少个数字就取多少个数字,但是这个函数不会一开始就生成好某个长度的序列,而是你每次获取一个新的数字的时候,它是根据上一个状态计算这个数字,然后只保存函数当前的执行结果状态,可以一直无限获取下去。python在版本2.2引入了这个思想,这个关键词就是yield!

3. yield and Generator

yield从字面理解就是产生某个东西,它其实本质上是一个代码流程控制语句,和if, for, while这种代码控制语句是同一个层次的东西。那么它控制了什么?或者到底产生了什么了呢?答案就是:

所有包含 yield 语句的函数,都会被python编译成一个生成器(Generator)

问题又来了,啥是生成器呢?

生成器就是“惰性计算”这个概念的实现载体!通过生成器来实现“惰性计算”!

废话不多说,上代码(例子3-1)!

def fib():
    a, b = 0, 1
    while True:
        yield a
        a, b = a+b, a
fib_generator = fib()
print(type(fib_generator)) # type一下其类型会输出:generator
print(next(fib_generator)) # 1
print(next(fib_generator)) # 1
print(next(fib_generator)) # 2
print(next(fib_generator)) # 3
print(next(fib_generator)) # 5
print(next(fib_generator)) # 8

这个fib_generator就是一个生成器,可以无穷尽产生fibnacci数列,你想要多少就可以取多少(想象如果你自己的银行卡也是一个生成器那该多美好 -_-!)
回想一下在讲 迭代器 的概念的时候,我们说任何迭代器都可以使用for in, 而生成器是一种特殊的迭代器,这个fib_generator当然也是可以for in的。
生成器的迭代和我们对一个list_iterator的迭代有什么本质的区别呢?答案就是yield引入的惰性计算,只有你在next(generator)的时候才会去计算出相应的值,而你在next(list_iterator)的时候,里面的值是早就存在的。

总结一下生成器的具体规则:

  1. 所有包含yield的函数都会被python解释器“解释”成一个生成器。
  2. 生成器中有yield语句的地方,每次next(generator)代码按逻辑顺序执行到yield处,都会返回yield后面表达式的值,然后暂停等待下一个next,继续按逻辑顺序执行。

承接上面的例子3-1,到这里,逻辑上我们可以执行这样的代码:

next(fib_generator)
do_something()
next(fib_generator)

因为生成器保留函数上一次执行的堆栈信息,所以我们在两次next之间完全可以执行其他代码!现在请你思考一下,这种功能有什么用?
····
你隐约是不是想到了什么,但又不是太清晰?没关系,我们继续复盘这种逻辑演化。

4.generator.send() and Coroutine

在python 2.5版本中,为生成器加入了一个至关重要的API,它就是send方法。这个send干什么用呢?

>>> def one_coroutine():
        got_string = yield
        print('i got:', got_string)
>>> c = one_coroutine()
>>> next(c) # 启动生成器,简单理解就是生成器需要执行到yield处暂停。
>>> c.send('something')
 i got: something
 StopIteration   Traceback (most recent call last)

注意这里的yield和之前的用法有个重大区别,那就是之前的用法是 yield+表达式,此处yield是一个赋值语句的右边,表示等待一个值,将其赋值给左边。我们使用send方法为生成器发送了一个字符串,然后生成器立即获取字符串并执行了生成器后面的代码。请回忆一下之前提到的生成器执行规则,会遇到yield暂停,这里代码执行下去不能再遇到新的yield,所以生成器抛出StopIteration,结束了生成器,我们可以把代码改一下,然后就能不断的给生成器发送字符串了:

def one_coroutine():
    while True:
        got_string = yield
        print('i got:', got_string)

这里我们已经完成了一个最简洁的协程。

待续:彻底搞懂python协程-第二篇(关键词5-10)

5. Event Loop 事件循环

6. Future/Task

7. 同步和异步

8. 阻塞和非阻塞

9. asyncio

10. tornado

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容