我现在有一个串行的代码,长这样:
for t in range(100000):
A(t+1) = fun_A(B(t))
B(t+1) = fun_B(A(t))
fun_A(), fun_B() 是我自己写的两个函数,分别需要上一个循环中对方的输出作为输入。
现在有没有办法将 fun_A(), fun_B() 在一个循环内并行执行?用多线程的话因为 CPython 存在全局锁可能实际上是串行执行,多进程的话不知道会不会额外增加两个函数间的数据传递的 I/O 开销。
各位有没有什么其他实现的思路?
1
SingeeKing 2020-10-06 10:34:47 +08:00 via iPhone
这是典型的用 Python 必有额外开销的问题。换语言吧
|
2
wander639 2020-10-06 10:49:20 +08:00
用 go 实现吧
|
3
threebr OP |
4
laike9m 2020-10-06 11:14:18 +08:00 via Android
A(t+1) 这个语法没看懂,你是想写中括号?
|
5
BiteTheDust 2020-10-06 11:16:15 +08:00 2
A(t)->B(t+1)->A(t+2)->B(t+3)....
B(t)->A(t+1)..... 这两个直接分开多进程执行如何呢 |
6
laike9m 2020-10-06 11:16:33 +08:00 via Android
如果是中括号的话,你这个就是没法并行,换什么语言都没用。我能想到的优化就是 lru 一下 A 和 B,避免对相同参数重复计算
|
8
whenov 2020-10-06 11:26:54 +08:00
你画出来流程就会发现是两条不重合的计算链,用两个进程分别计算即可。计算过程中无需共享数据,结束后交换两个数组的偶数位。
|
9
makdon 2020-10-06 11:28:53 +08:00 1
如果 func_A 或 B 内涉及外部 IO 例如网络等,这俩并行的话还是可以提高那么一丢丢性能的,不过在这个 case 里面个人更倾向于优化 func_A 和 func_B 的性能为主,可以先做下 benchmark 看看瓶颈在哪
|
10
youngce 2020-10-06 11:34:57 +08:00 2
实际上对整体性能的提升不会太大的。写 python 太多新手,一不做性能分析,二不做测试,自己不小心写出一堆阻塞逻辑,最后怪 python 慢。实际上为什么 go 这么火,一定程度也是因为可以让菜鸟轻松写出性能不错的代码
|
11
Wicked 2020-10-06 11:56:06 +08:00 via iPhone
从顶楼的代码看不适合并行,每一次循环都依赖来自另外一条线的输出。另外,Python 优先考虑多进程。
|
12
lpts007 2020-10-06 12:01:12 +08:00
如果想改并行,说明慢,慢说明是 python 问题,那么改成 go 问题就消失了。
请 python 新手谨遵以上原则 |
13
imn1 2020-10-06 12:03:39 +08:00
看样子很适合 pandas 的 rolling 函数(移动计算)
|
14
lxy42 2020-10-06 12:07:14 +08:00
把计算流程展开你就会发现:A[n] = fun_A(B[n - 1]) = fun_A(fun_B(A[n - 2])),A 的计算其实和 B 没有太大关系。
|
15
yangxin0 2020-10-06 12:45:56 +08:00 1
写 python 扩展,在 c/c++里面就没有 GIL 了
|
16
huskar 2020-10-06 22:40:11 +08:00 via Android
这和 GIL 有啥关系啊……纯粹是楼主自己没想明白,像楼上说的拆成两个序列分别算就好。
各位说换语言、换 go 、写 c 的亮下代码?想知道怎么写能满足楼主需求。 |
17
black11black 2020-10-06 22:47:32 +08:00 1
@huskar 他的意思是我用多线程,就遇到 GIL 的问题,所以如果不愿意换语言,一般来说解决方法开销从低到高有:1 、换 JIT 解释器 2 、多进程 3 、用魔法 JIT 搞定一些计算密集部分 4 、计算密集部分用 cython 替代
|
19
sunhk25 2020-10-07 07:58:29 +08:00 via Android
线程的话开销比会很大吗
|
21
threebr OP @sunhk25 我还没有开始实践,只是网上的说法如此,线程比进程更轻量,切换线程的上下文开销和线程间数据同步的开销都比进程小
|
22
huskar 2020-10-07 13:06:23 +08:00 via Android
@black11black 我是说楼主这需求跟 gil 没关系。比如用 c,没有 gil,该怎么写?
|
23
black11black 2020-10-07 21:41:14 +08:00
@threebr 理论上线程也需要进行内核态切换,不像协程局限在用户态内,所以 asyncio 的出现极大地拓展了 py 的 IO 相关处理能力,和进程有多大差距应该是在内存部分,具体的没了解到非常详细的部分。但是线程切换是有切片时间的,比如一种情况是比如你计划在一秒内转换一万次线程,这种密度上使用多线程会导致效率降低很多
|