Python 的协程到底有啥用啊…

2020-03-23 23:11:47 +08:00
 nightan
看了好多文章,也自己尝试用了用协程,但是感觉对程序的运行效率并没什么太大的提升…
我原以为我可以在通过 HTTP 取数据的这个时间内让程序去处理别的逻辑,处理完后再回来处理取回来的数据…
可能是我太菜了…(捂脸)
7889 次点击
所在节点    Python
45 条回复
YUX
2020-03-24 10:35:56 +08:00
也可以试试 multiprocessing
nightan
2020-03-24 14:23:23 +08:00
@YUX 感谢大佬的分享,前后大概看得懂……中间看的懵圈……(捂脸),我得慢慢消化消化……
我现在写的程序中,实际上有三个函数,分别负责——
- 1. 从某个数据库读数据,存下来
- 2. 处理这些数据,然后写到另一个库中,同时这些处理后的数据还要让第三个函数拿到
- 3. 把处理后的数据通过 HTTP 发送出去
也许我可以把这三个函数放到三个线程中?其中一个函数发生 I/O 操作的时候,其它函数应该会执行吧……?
YUX
2020-03-24 14:31:06 +08:00
@nightan #22 正如前面多次提到的 要全局都非阻塞 不知道你这三个函数是否都满足要求 推荐一个 非阻塞的 orm https://github.com/tortoise/tortoise-orm
Orenoid
2020-03-24 15:04:29 +08:00
推荐一篇文章,https://snarky.ca/how-the-heck-does-async-await-work-in-python-3-5/
作者从头讲解了 Python 协程的工作原理,并实现了一个简易的事件循环,有助于理解基于 Python 协程的工作原理。
但是这个说的是原理,目前可能不太适合你看。之后有兴趣可以看下,看完可以再读下 asyncio 库的源码。
Python 协程本质是依赖 IO 多路复用和 yield 去实现异步的,所以只有网络 IO 才有必要使用协程。
nightan
2020-03-24 15:16:37 +08:00
@YUX 发 HTTP 请求用的 requests 模块,看起来是阻塞的,刚刚我也试过,await 对于这个模块的调用不生效; 所以即使我用多线程,在处理 HTTP 请求的时候,因为是阻塞的,也一定是要等它执行完是吗?阻塞的 I/O 发生时,python 也不能切换到别的线程咯……
crackhopper
2020-03-24 16:07:05 +08:00
你得整体在一个异步框架里,才有意义。比如事件驱动的框架。
freakxx
2020-03-24 17:18:22 +08:00
xcstream
2020-03-24 17:23:07 +08:00
无锁并发
nightan
2020-03-24 19:21:53 +08:00
@freakxx 谢谢
hehheh
2020-03-24 20:13:12 +08:00
我以前写过一个代理 ip 池,测试 1000 个 IP 。如果是多线程大概需要 2 分钟,如果是协程大概 10 秒。
keepeye
2020-03-24 21:17:28 +08:00
我原以为我可以在通过 HTTP 取数据的这个时间内让程序去处理别的逻辑,处理完后再回来处理取回来的数据
====
你不会以为协程只能 await 吧? asyncio.ensure_feature 以及 asyncio.gather 了解过么?
nightan
2020-03-24 21:43:11 +08:00
@keepeye 看了楼上大佬分享的博客,asyncio.ensure_feature 有用到……效果明显……但是要用 requests_async,requests 本身是阻塞的似乎没办法……
keepeye
2020-03-24 21:45:39 +08:00
@nightan aiohttp aiomysql 等等 https://github.com/aio-libs
nightan
2020-03-24 23:29:01 +08:00
@keepeye 谢谢!
ClericPy
2020-03-25 00:00:13 +08:00
@nightan #32 本身阻塞的就用 run_in_executor 吧, 丢一个线程让它玩儿去. 多看看 encode 和 aiolibs 里的经典库, 看文档灵光乍现, 看源码茅塞顿开
black11black
2020-03-25 00:16:06 +08:00
> 我原以为我可以在通过 HTTP 取数据的这个时间内让程序去处理别的逻辑,处理完后再回来处理取回来的数据…

↑ 异步确实是给你干这个的
SmartKeyerror
2020-03-25 11:12:51 +08:00
协程的本质是保存当前函数或者例程的运行状态,并主动让出 CPU 资源,使得和当前函数处于"平级"的函数或者是例程能够得到 CPU 资源,并于原有保存点继续执行,整个过程只有少量的函数运行点恢复操作,没有重量级的线程(进程)上下文切换,所以在同样任务的情况下,协程比线程、进程拥有更高的执行效率。
Python 的协程,对我个人而言还不如线程好用,宁愿使用 gevent patch,也不愿意使用 asyncio 。协程还是 Golang 用起来更加顺手。
raymanr
2020-03-25 11:39:11 +08:00
我这两天也在看这个, 完全不能理解 async await 的意义...
一般函数不也是要等他返回结果吗? 为啥要 await ...
我不做爬虫不写服务器, 平时只和 numpy scipy pandas 打交道, 是不是异步对我其实没啥用 ?
MinQ
2020-03-25 14:52:33 +08:00
@raymanr 这种一般都用多线程吧,把数据从原始状态转换成某种结构化形式丢去学习,我用 joblib 就比普通循环快几十条街
lithbitren
2020-03-25 17:26:19 +08:00
协程仅使用于类似爬虫或服务这种持续性 io 密集的程序,其他平砍算法可以解决的事情用协程就是增加心智负担。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/655539

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX