Python 核心技术与实战
景霄
Facebook 资深工程师
78765 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 47 讲
开篇词 (1讲)
Python 核心技术与实战
15
15
1.0x
00:00/00:00
登录|注册

20 | 揭秘 Python 协程

你好,我是景霄。
上一节课的最后,我们留下一个小小的悬念:生成器在 Python 2 中还扮演了一个重要角色,就是用来实现 Python 协程。
那么首先你要明白,什么是协程?
协程是实现并发编程的一种方式。一说并发,你肯定想到了多线程 / 多进程模型,没错,多线程 / 多进程,正是解决并发问题的经典模型之一。最初的互联网世界,多线程 / 多进程在服务器并发中,起到举足轻重的作用。
随着互联网的快速发展,你逐渐遇到了 C10K 瓶颈,也就是同时连接到服务器的客户达到了一万个。于是很多代码跑崩了,进程上下文切换占用了大量的资源,线程也顶不住如此巨大的压力,这时, NGINX 带着事件循环出来拯救世界了。
如果将多进程 / 多线程类比为起源于唐朝的藩镇割据,那么事件循环,就是宋朝加强的中央集权制。事件循环启动一个统一的调度器,让调度器来决定一个时刻去运行哪个任务,于是省却了多线程中启动线程、管理线程、同步锁等各种开销。同一时期的 NGINX,在高并发下能保持低资源低消耗高性能,相比 Apache 也支持更多的并发连接。
再到后来,出现了一个很有名的名词,叫做回调地狱(callback hell),手撸过 JavaScript 的朋友肯定知道我在说什么。我们大家惊喜地发现,这种工具完美地继承了事件循环的优越性,同时还能提供 async / await 语法糖,解决了执行性和可读性共存的难题。于是,协程逐渐被更多人发现并看好,也有越来越多的人尝试用 Node.js 做起了后端开发。(讲个笑话,JavaScript 是一门编程语言。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Python 核心技术与实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(123)

  • 最新
  • 精选
  • Jingxiao
    置顶
    思考题答案: 在 python 3.7 及以上的版本中,我们对 task 对象调用 add_done_callback() 函数,即可绑定特定回调函数。回调函数接受一个 future 对象,可以通过 future.result() 来获取协程函数的返回值。 示例如下: import asyncio async def crawl_page(url): print('crawling {}'.format(url)) sleep_time = int(url.split('_')[-1]) await asyncio.sleep(sleep_time) return 'OK {}'.format(url) async def main(urls): tasks = [asyncio.create_task(crawl_page(url)) for url in urls] for task in tasks: task.add_done_callback(lambda future: print('result: ', future.result())) await asyncio.gather(*tasks) %time asyncio.run(main(['url_1', 'url_2', 'url_3', 'url_4'])) 输出: crawling url_1 crawling url_2 crawling url_3 crawling url_4 result: OK url_1 result: OK url_2 result: OK url_3 result: OK url_4 Wall time: 4 s
    41
  • Jingxiao
    置顶
    发现评论区好多朋友说无法运行,在这里统一解释下: 1. %time 是 jupyter notebook 自带的语法糖,用来统计一行命令的运行时间;如果你的运行时是纯粹的命令行 python,或者 pycharm,那么请把 %time 删掉,自己用传统的时间戳方法来记录时间也可以;或者使用 jupyter notebook 2. 我的本地解释器是 Anaconda Python 3.7.3,亲测 windows / ubuntu 均可正常运行,如无法执行可以试试 pip install nest-asyncio,依然无法解决请尝试安装 Anaconda Python 3. 这次代码因为使用了较新的 API,所以需要较新的版本号,但是朋友们依然出现了一些运行时问题,这里先表示下歉意;同时也想说明的是,在提问之前自己经过充分搜索,尝试后解决问题,带来的快感,和能力的提升,相应也是很大的,一门工程最需要的是 hands on dirty work(动手做脏活),才能让自己的能力得到本质的提升,加油!
    10
    75
  • Airnm.毁
    豆瓣那个发现requests.get(url).content/text返回都为空,然后打了下status_code发现是418,网上找418的解释,一般是网站反爬虫基础机制,需要加请求头模仿浏览器就可跳过,改为下面的样子就可通过:url = "https://movie.douban.com/cinema/later/beijing/" head={ 'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36', 'Referer':'https://time.geekbang.org/column/article/101855', 'Connection':'keep-alive'} res = requests.get(url,headers=head)

    作者回复: 👍,可能是增加了反爬虫机制

    3
    6
  • jackstraw
    有点没明白,前面说任务创建后立马就开始执行了么?怎么后面在解密底层运行过程的时候,说任务创建后等待执行?到底是哪一个呀?

    作者回复: 原文是“任务创建后很快就会被调度执行”,并不是“立马就开始执行”;其次在解密底层运行时,main 函数也可以理解为一个正常的 task,要等这个 task 进入 await 的状态,才会调度下一个 task

    2
  • 长期规划
    老师,在最后那个协程例子中为何没用requests库呢?是因为它不支持协程吗

    作者回复: 协程使用的是 aiohttp 并发网络 io 库,因此就不需要 requests 了

    1
  • 一凡
    协程是单线程怎么理解?所有的协程都是吗

    作者回复: 对 单线程实现并发

  • 苹果
    asyncio.run() cannot be called from a running event loop 这个问题是如何解决,

    作者回复: https://stackoverflow.com/questions/55409641/asyncio-run-cannot-be-called-from-a-running-event-loop

  • 隰有荷
    老师,在如下代码中: async def worker_2(): print('worker_2 start') await asyncio.sleep(2) print('worker_2 done') 其中的await asyncio.sleep(2)是否可以理解为在切出当前程序,2秒后再继续执行print('worker_2 done')代码? 那么如果我有个耗时任务 def xxx(): ...,那么该如何用await asyncio来让这个xxx函数运行并切出当前程序呢?

    作者回复: 1. 基本是,但是注意是2秒后将当前断点加入协程池中等待调度。 2. 如果你只有这个耗时任务和当前任务(也就是总共两个任务),在当前任务调用 await 自动就切换到耗时任务了;但是当协程任务很多的时候,由于协程没有优先级设置,因此可能会出现耗时任务一直没有被分配资源的情况。实践中可以创建一个用于完成耗时任务的协程池,以限制耗时任务占用的总协程数量,于是就又回到了基于线程的并发模型中。

  • SUN
    Jupyter 中运行 %time asyncio.run(main(['url_1', 'url_2', 'url_3', 'url_4'])) 会报错: RuntimeError: asyncio.run() cannot be called from a running event loop Python、Anaconda、Jupyter都安装了。 话说:Jupyter不就是为了消除个人本地开发环境差异性而诞生的吗?这个结果有点反讽。 各位学员的留言都看了,没人解决了此问题……

    作者回复: https://stackoverflow.com/questions/55409641/asyncio-run-cannot-be-called-from-a-running-event-loop

    2
  • 扶幽
    请问下有木有相关的书籍,来进行这块的学习呢!有些原理性的东西还是没办法深入理解,谢谢。

    作者回复: 最好的办法就是多实践。文中的原理性东西都已经讲了,你可以边实践,遇到问题再去google

收起评论
显示
设置
留言
99+
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部