【妙用协程】 – 协程当然可以用来处理I/O阻塞问题
admin
2023-07-31 01:50:33
0

前面讲的两个协程的用途,一个是用来使用协程表达工作流里的流程的概念,一个是用协程来表达一个动画的播放过程。总结起来,就是用协程来解决带有流程阻塞的代码逻辑组织的问题。但是协程并不是生来干这个的,协程最主流的用途是一种用于处理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操作完成了再从上次放弃执行的地方继续执行后面的语句。

相关内容

热门资讯

Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
项目管理和工程管理的区别 项目管理 项目管理,顾名思义就是专注于开发和完成项目的管理,以实现目标并满足成功标准和项目要求。 工...