V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
threebr
V2EX  ›  问与答

Python 如何避免线程间的全局锁 GIL 进行并行计算?

  •  1
     
  •   threebr · 2020-10-06 10:20:56 +08:00 · 2597 次点击
    这是一个创建于 1543 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我现在有一个串行的代码,长这样:

    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 开销。

    各位有没有什么其他实现的思路?

    23 条回复    2020-10-07 21:41:14 +08:00
    SingeeKing
        1
    SingeeKing  
       2020-10-06 10:34:47 +08:00 via iPhone
    这是典型的用 Python 必有额外开销的问题。换语言吧
    wander639
        2
    wander639  
       2020-10-06 10:49:20 +08:00
    用 go 实现吧
    threebr
        3
    threebr  
    OP
       2020-10-06 11:09:35 +08:00
    @SingeeKing
    @wander639

    换语言我个人的时间成本太高了,效果也难以估计,只能是最后的办法
    laike9m
        4
    laike9m  
       2020-10-06 11:14:18 +08:00 via Android
    A(t+1) 这个语法没看懂,你是想写中括号?
    BiteTheDust
        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).....
    这两个直接分开多进程执行如何呢
    laike9m
        6
    laike9m  
       2020-10-06 11:16:33 +08:00 via Android
    如果是中括号的话,你这个就是没法并行,换什么语言都没用。我能想到的优化就是 lru 一下 A 和 B,避免对相同参数重复计算
    threebr
        7
    threebr  
    OP
       2020-10-06 11:23:13 +08:00 via Android
    @laike9m 是中括号,只在单个循环内部还是可以把两个函数改成并行的
    whenov
        8
    whenov  
       2020-10-06 11:26:54 +08:00
    你画出来流程就会发现是两条不重合的计算链,用两个进程分别计算即可。计算过程中无需共享数据,结束后交换两个数组的偶数位。
    makdon
        9
    makdon  
       2020-10-06 11:28:53 +08:00   ❤️ 1
    如果 func_A 或 B 内涉及外部 IO 例如网络等,这俩并行的话还是可以提高那么一丢丢性能的,不过在这个 case 里面个人更倾向于优化 func_A 和 func_B 的性能为主,可以先做下 benchmark 看看瓶颈在哪
    youngce
        10
    youngce  
       2020-10-06 11:34:57 +08:00   ❤️ 2
    实际上对整体性能的提升不会太大的。写 python 太多新手,一不做性能分析,二不做测试,自己不小心写出一堆阻塞逻辑,最后怪 python 慢。实际上为什么 go 这么火,一定程度也是因为可以让菜鸟轻松写出性能不错的代码
    Wicked
        11
    Wicked  
       2020-10-06 11:56:06 +08:00 via iPhone
    从顶楼的代码看不适合并行,每一次循环都依赖来自另外一条线的输出。另外,Python 优先考虑多进程。
    lpts007
        12
    lpts007  
       2020-10-06 12:01:12 +08:00
    如果想改并行,说明慢,慢说明是 python 问题,那么改成 go 问题就消失了。

    请 python 新手谨遵以上原则
    imn1
        13
    imn1  
       2020-10-06 12:03:39 +08:00
    看样子很适合 pandas 的 rolling 函数(移动计算)
    lxy42
        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 没有太大关系。
    yangxin0
        15
    yangxin0  
       2020-10-06 12:45:56 +08:00   ❤️ 1
    写 python 扩展,在 c/c++里面就没有 GIL 了
    huskar
        16
    huskar  
       2020-10-06 22:40:11 +08:00 via Android
    这和 GIL 有啥关系啊……纯粹是楼主自己没想明白,像楼上说的拆成两个序列分别算就好。
    各位说换语言、换 go 、写 c 的亮下代码?想知道怎么写能满足楼主需求。
    black11black
        17
    black11black  
       2020-10-06 22:47:32 +08:00   ❤️ 1
    @huskar 他的意思是我用多线程,就遇到 GIL 的问题,所以如果不愿意换语言,一般来说解决方法开销从低到高有:1 、换 JIT 解释器 2 、多进程 3 、用魔法 JIT 搞定一些计算密集部分 4 、计算密集部分用 cython 替代
    sunhk25
        18
    sunhk25  
       2020-10-07 07:56:44 +08:00 via Android
    sunhk25
        19
    sunhk25  
       2020-10-07 07:58:29 +08:00 via Android
    线程的话开销比会很大吗
    sunhk25
        20
    sunhk25  
       2020-10-07 07:58:47 +08:00 via Android
    @sunhk25 进程
    threebr
        21
    threebr  
    OP
       2020-10-07 10:07:38 +08:00 via Android
    @sunhk25 我还没有开始实践,只是网上的说法如此,线程比进程更轻量,切换线程的上下文开销和线程间数据同步的开销都比进程小
    huskar
        22
    huskar  
       2020-10-07 13:06:23 +08:00 via Android
    @black11black 我是说楼主这需求跟 gil 没关系。比如用 c,没有 gil,该怎么写?
    black11black
        23
    black11black  
       2020-10-07 21:41:14 +08:00
    @threebr 理论上线程也需要进行内核态切换,不像协程局限在用户态内,所以 asyncio 的出现极大地拓展了 py 的 IO 相关处理能力,和进程有多大差距应该是在内存部分,具体的没了解到非常详细的部分。但是线程切换是有切片时间的,比如一种情况是比如你计划在一秒内转换一万次线程,这种密度上使用多线程会导致效率降低很多
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5541 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 06:38 · PVG 14:38 · LAX 22:38 · JFK 01:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.