Python 的协程到底有啥用啊…

2020-03-23 23:11:47 +08:00
 nightan
看了好多文章,也自己尝试用了用协程,但是感觉对程序的运行效率并没什么太大的提升…
我原以为我可以在通过 HTTP 取数据的这个时间内让程序去处理别的逻辑,处理完后再回来处理取回来的数据…
可能是我太菜了…(捂脸)
8192 次点击
所在节点    Python
45 条回复
LokiSharp
2020-03-23 23:15:41 +08:00
你得所有都异步非阻塞才行
ipwx
2020-03-23 23:24:17 +08:00
ClericPy
2020-03-23 23:24:48 +08:00
全局协程写起来有爽的地方也有不习惯的地方, 爽的基本就是全程非阻塞了, 以前多线程处理的事情全丢给 Future/Task, 整个程序基本不会因为一句代码影响其他代码(写错的情况下还是可能的... 比如错用 time.sleep). 不爽的地方就是程序不能自己识别自己要不要 await 一个结果, 害我为了兼容普通函数和协程的执行结果, 总得

result = (await result) if isawaitable(result) else xxx

性能的话, 不开 uvloop 感觉不出太明显差距
mimzy
2020-03-23 23:34:54 +08:00
用同步的思维写异步程序
减少锁、上下文切换、线程自身的开销
mimzy
2020-03-23 23:35:07 +08:00
For I/O-bound workloads, there are exactly (only!) two reasons to use async-based concurrency over thread-based concurrency:

- Asyncio offers a safer alternative to preemptive multitasking (i.e., using threads), thereby avoiding the bugs, race conditions, and other nondeterministic dangers that frequently occur in nontrivial threaded applications.

- Asyncio offers a simple way to support many thousands of simultaneous socket connections, including being able to handle many long-lived connections for newer technologies like WebSockets, or MQTT for Internet of Things (IoT) applications.

摘自 Using Asyncio in Python 昨天刚好看了这本书 如果感兴趣且能看到的话可以看下 还是挺不错的 http://shop.oreilly.com/product/0636920320876.do
zhuangzhuang1988
2020-03-24 00:16:24 +08:00
xingheng
2020-03-24 01:27:18 +08:00
协程的意义在意执行多个没有上下文结果依赖的“不相关”的任务的时候会让这些任务并行执行,同时又不需要担心线程的状态管理,以此达到运行效率的提升。
但是,有一种情况下协程并不会提升效率,理论上反而会降低效率(因为线程切换的代价)。

async def run(tasks):
all_results = []
for task in tasks:
result = await execute(task) # the only one await
all_results.append(result) # append logic result of execute, not task itself

return all_results

不是特别好的一个例子。只有一个 await task 的话,后续操作又需要拿到结果才能继续,相当于同步的 join 卡在了 caller 所在的线程,没有异步的意义,所以会更慢。当然,基于上面的例子要优化也是非常简单的,不写了
sylvos
2020-03-24 07:15:39 +08:00
@xingheng 还请写下优化的代码
janxin
2020-03-24 07:54:28 +08:00
因为没有理解并发并行的含义吧...
YUX
2020-03-24 08:20:32 +08:00
https://hatboy.github.io/2019/02/16/Python 异步编程详解 /

推荐一篇好文章
nightan
2020-03-24 09:19:54 +08:00
@xingheng 我好像就是写了个这样的东西(捂脸)
nightan
2020-03-24 09:20:34 +08:00
@YUX 大佬 404 了这个……
nightan
2020-03-24 09:31:22 +08:00
@xingheng 大佬,求优化的例子……
jatsz
2020-03-24 09:32:28 +08:00
协程-主要还是保持状态,像你这种还是需要异步 IO,asyncio 。
在应用上,主要还是生成器,比如你处理未知网络数据,你可以使用协程去迭代处理。
https://www.imzjy.com/blog/2015-01-01-coroutine
itskingname
2020-03-24 09:39:35 +08:00
我写了一篇文章来说明你遇到的问题。https://mp.weixin.qq.com/s/spayiLNuTnFVOWWeW-jkwQ

注意文中为了照顾没有基础的读者,有些概念可能并不十分准确,但是表达意思。
bnm965321
2020-03-24 10:07:16 +08:00
当然可以在 HTTP 取数据的时间干其他的事情,就算是做 CPU bound 的事情也可以。如果你从头写一个爬虫,一次多发一些 HTTP request 就知道了。HTTP 堵塞的那些时间,CPU 是可以做很多很多事情的
smallgoogle
2020-03-24 10:10:51 +08:00
反正我知道协程速度快很多就对了。
YUX
2020-03-24 10:21:37 +08:00
freakxx
2020-03-24 10:27:52 +08:00
> 这个时间内让程序去处理别的逻辑,处理完后再回来处理取回来的数据

这个地方读起来有些怪


之前是写了一个 chunk + requests_async 用协程处理

你可以这么理解

for _ in range(100):
request


for _ in range(100):
request_async


这两者会有区别。

但如果
你只是请求一个并直接使用,不一定有你要的效果。
vicalloy
2020-03-24 10:28:51 +08:00
协程是单线程的,因此你必须保证你的所有“阻塞”操作都是异步的,不然对性能没有任何提升。
比如你用 requests 写爬虫程序。由于 requests 的操作都是阻塞的,用协程不会带来任何的性能提升。
要想提升性能得把 requests 换成非阻塞的库,如 aiohttp 。

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

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

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

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

© 2021 V2EX