前面讲的两个协程的用途,一个是用来使用协程表达工作流里的流程的概念,一个是用协程来表达一个动画的播放过程。总结起来,就是用协程来解决带有流程阻塞的代码逻辑组织的问题。但是协程并不是生来干这个的,协程最主流的用途是一种用于处理I/O阻塞的工具。I/O阻塞的挑战是多重的,一方面是有很多人研究高并发低延迟之类的问题,另外一方面I/O阻塞对于代码逻辑的组织挑战也是巨大的。比如最经典的基于回调的I/O阻塞编码风格,下面是一个使用Twisted框架的代码示例(摘自:https://github.com/feihong/tulip-talk/blob/master/examples):

from twisted.internet import reactor
from twisted.internet.defer import Deferred, succeed
from twisted.internet.protocol import Protocol
from twisted.web.client import Agent

def print_headers(response):
    for k, v in response.headers.getAllRawHeaders():
        print(\'{}: {}\'.format(k, v[0][:80]))

    return get_response_body(response)

def get_response_body(response):
    class BodyReceiver(Protocol):
        def dataReceived(self, data):
            chunks.append(data)
        def connectionLost(self, reason):
            finished.callback(\'\'.join(chunks))

    finished = Deferred()
    chunks = []
    response.deliverBody(BodyReceiver())
    return finished

def print_body(data):
    print(\'\\nReceived {} bytes.\\n\'.format(len(data)))
    return succeed(None)

if __name__ == \'__main__\':
    agent = Agent(reactor)
    d = agent.request(\'GET\', \'http://megafeihong.tumblr.com\')
    d.addCallback(print_headers)
    d.addCallback(print_body)
    d.addCallback(lambda x: reactor.stop())
    reactor.run()

代码逻辑是不是非常不好懂?究其原因在于一个顺序的执行过程,因为中间的I/O阻塞被拆成了意大利面条式的破碎逻辑。而是用协程就可以很好的实现Logic Locality,把上下相关的代码放在一段函数内:

import tulip
from tulip import http

@tulip.coroutine
def download(url):
    response = yield from http.request(\'GET\', url)
    for k, v in response.items():
        print(\'{}: {}\'.format(k, v[:80]))

    data = yield from response.read()
    print(\'\\nReceived {} bytes.\\n\'.format(len(data)))

if __name__ == \'__main__\':
    loop = tulip.get_event_loop()
    coroutine = download(\'http://omegafeihong.tumblr.com\')
    loop.run_until_complete(coroutine)

这段代码是不是容易懂多了?这个框架叫tulip,是Python基于协程,确切说是基于generator的网络异步I/O编程框架。其中使用了一个新的yield from语法,暂时不用深究,基本上和yield是一个意思,代表函数在这个地方放弃执行,让外部去把I/O处理完,等I/O操作完成了再从上次放弃执行的地方继续执行后面的语句。