1
LokiSharp 2020-03-23 23:15:41 +08:00
你得所有都异步非阻塞才行
|
2
ipwx 2020-03-23 23:24:17 +08:00
|
3
ClericPy 2020-03-23 23:24:48 +08:00
全局协程写起来有爽的地方也有不习惯的地方, 爽的基本就是全程非阻塞了, 以前多线程处理的事情全丢给 Future/Task, 整个程序基本不会因为一句代码影响其他代码(写错的情况下还是可能的... 比如错用 time.sleep). 不爽的地方就是程序不能自己识别自己要不要 await 一个结果, 害我为了兼容普通函数和协程的执行结果, 总得
result = (await result) if isawaitable(result) else xxx 性能的话, 不开 uvloop 感觉不出太明显差距 |
4
mimzy 2020-03-23 23:34:54 +08:00
用同步的思维写异步程序
减少锁、上下文切换、线程自身的开销 |
5
mimzy 2020-03-23 23:35:07 +08:00 1
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 |
6
zhuangzhuang1988 2020-03-24 00:16:24 +08:00
http://www.dabeaz.com/finalgenerator/index.html
超全, 超牛逼, 超好看 |
7
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 所在的线程,没有异步的意义,所以会更慢。当然,基于上面的例子要优化也是非常简单的,不写了 |
9
janxin 2020-03-24 07:54:28 +08:00
因为没有理解并发并行的含义吧...
|
10
YUX 2020-03-24 08:20:32 +08:00 via iPhone
|
14
jatsz 2020-03-24 09:32:28 +08:00
协程-主要还是保持状态,像你这种还是需要异步 IO,asyncio 。
在应用上,主要还是生成器,比如你处理未知网络数据,你可以使用协程去迭代处理。 https://www.imzjy.com/blog/2015-01-01-coroutine |
15
itskingname 2020-03-24 09:39:35 +08:00 2
我写了一篇文章来说明你遇到的问题。https://mp.weixin.qq.com/s/spayiLNuTnFVOWWeW-jkwQ
注意文中为了照顾没有基础的读者,有些概念可能并不十分准确,但是表达意思。 |
16
bnm965321 2020-03-24 10:07:16 +08:00
当然可以在 HTTP 取数据的时间干其他的事情,就算是做 CPU bound 的事情也可以。如果你从头写一个爬虫,一次多发一些 HTTP request 就知道了。HTTP 堵塞的那些时间,CPU 是可以做很多很多事情的
|
17
smallgoogle 2020-03-24 10:10:51 +08:00
反正我知道协程速度快很多就对了。
|
18
YUX 2020-03-24 10:21:37 +08:00
|
19
freakxx 2020-03-24 10:27:52 +08:00
> 这个时间内让程序去处理别的逻辑,处理完后再回来处理取回来的数据
这个地方读起来有些怪 之前是写了一个 chunk + requests_async 用协程处理 你可以这么理解 for _ in range(100): request 和 for _ in range(100): request_async 这两者会有区别。 但如果 你只是请求一个并直接使用,不一定有你要的效果。 |
20
vicalloy 2020-03-24 10:28:51 +08:00
协程是单线程的,因此你必须保证你的所有“阻塞”操作都是异步的,不然对性能没有任何提升。
比如你用 requests 写爬虫程序。由于 requests 的操作都是阻塞的,用协程不会带来任何的性能提升。 要想提升性能得把 requests 换成非阻塞的库,如 aiohttp 。 |
21
YUX 2020-03-24 10:35:56 +08:00
也可以试试 multiprocessing
|
22
nightan OP @YUX 感谢大佬的分享,前后大概看得懂……中间看的懵圈……(捂脸),我得慢慢消化消化……
我现在写的程序中,实际上有三个函数,分别负责—— - 1. 从某个数据库读数据,存下来 - 2. 处理这些数据,然后写到另一个库中,同时这些处理后的数据还要让第三个函数拿到 - 3. 把处理后的数据通过 HTTP 发送出去 也许我可以把这三个函数放到三个线程中?其中一个函数发生 I/O 操作的时候,其它函数应该会执行吧……? |
23
YUX 2020-03-24 14:31:06 +08:00
@nightan #22 正如前面多次提到的 要全局都非阻塞 不知道你这三个函数是否都满足要求 推荐一个 非阻塞的 orm https://github.com/tortoise/tortoise-orm
|
24
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 才有必要使用协程。 |
25
nightan OP @YUX 发 HTTP 请求用的 requests 模块,看起来是阻塞的,刚刚我也试过,await 对于这个模块的调用不生效; 所以即使我用多线程,在处理 HTTP 请求的时候,因为是阻塞的,也一定是要等它执行完是吗?阻塞的 I/O 发生时,python 也不能切换到别的线程咯……
|
26
crackhopper 2020-03-24 16:07:05 +08:00
你得整体在一个异步框架里,才有意义。比如事件驱动的框架。
|
27
freakxx 2020-03-24 17:18:22 +08:00
|
28
xcstream 2020-03-24 17:23:07 +08:00
无锁并发
|
30
hehheh 2020-03-24 20:13:12 +08:00
我以前写过一个代理 ip 池,测试 1000 个 IP 。如果是多线程大概需要 2 分钟,如果是协程大概 10 秒。
|
31
keepeye 2020-03-24 21:17:28 +08:00
我原以为我可以在通过 HTTP 取数据的这个时间内让程序去处理别的逻辑,处理完后再回来处理取回来的数据
==== 你不会以为协程只能 await 吧? asyncio.ensure_feature 以及 asyncio.gather 了解过么? |
32
nightan OP @keepeye 看了楼上大佬分享的博客,asyncio.ensure_feature 有用到……效果明显……但是要用 requests_async,requests 本身是阻塞的似乎没办法……
|
33
keepeye 2020-03-24 21:45:39 +08:00
@nightan aiohttp aiomysql 等等 https://github.com/aio-libs
|
35
ClericPy 2020-03-25 00:00:13 +08:00
@nightan #32 本身阻塞的就用 run_in_executor 吧, 丢一个线程让它玩儿去. 多看看 encode 和 aiolibs 里的经典库, 看文档灵光乍现, 看源码茅塞顿开
|
36
black11black 2020-03-25 00:16:06 +08:00
> 我原以为我可以在通过 HTTP 取数据的这个时间内让程序去处理别的逻辑,处理完后再回来处理取回来的数据…
↑ 异步确实是给你干这个的 |
37
SmartKeyerror 2020-03-25 11:12:51 +08:00
协程的本质是保存当前函数或者例程的运行状态,并主动让出 CPU 资源,使得和当前函数处于"平级"的函数或者是例程能够得到 CPU 资源,并于原有保存点继续执行,整个过程只有少量的函数运行点恢复操作,没有重量级的线程(进程)上下文切换,所以在同样任务的情况下,协程比线程、进程拥有更高的执行效率。
Python 的协程,对我个人而言还不如线程好用,宁愿使用 gevent patch,也不愿意使用 asyncio 。协程还是 Golang 用起来更加顺手。 |
38
raymanr 2020-03-25 11:39:11 +08:00
我这两天也在看这个, 完全不能理解 async await 的意义...
一般函数不也是要等他返回结果吗? 为啥要 await ... 我不做爬虫不写服务器, 平时只和 numpy scipy pandas 打交道, 是不是异步对我其实没啥用 ? |
40
lithbitren 2020-03-25 17:26:19 +08:00
协程仅使用于类似爬虫或服务这种持续性 io 密集的程序,其他平砍算法可以解决的事情用协程就是增加心智负担。
|
41
jwchen 2020-03-25 21:00:22 +08:00
go 的协程并发模型太漂亮了
@SmartKeyerror |
43
nightan OP @raymanr 我这这几天看下来我能感觉到协程有用但是我现在真的是写不好…我暂时先用多线程和队列来优化代码…http 部分我保持顺序执行就好了,因为我还发现我目标的服务器是按顺序处理请求的,同时多个请求过去反而会慢…
|
44
raymanr 2020-03-26 09:17:22 +08:00
@nightan 我暂时先搁置这个问题了, js 的 promise 我都可以理顺, async await 这种就是一直吃不懂, 始终对于异步的理解还在回调函数上面. 找不到回调函数在哪里就不知道发生了什么
|
45
adamwong 2020-04-13 17:13:51 +08:00
@SmartKeyerror 小龙,看看我发现了什么
|