Python中指针式传递的函数遇到的问题

最近在尝试通过 multiprocessing 把原来的计算核心改为通过多进程实现的并行程序,但碰到了一个非常奇怪的问题,经过一些时间的排查,终于找到了问题所在。虽然问题本身很简单,但也许也有一定典型性,尤其是对编程新手而言,因此在这里用最简单的模型重现一下。

首先从下面一段非常简单的程序开始:

def main():
    x = [1, 2, 3, 4, 5]
    foo(x)
    print(x)

def foo(x):
    bar(x)
    # x = bar2(x)
    for i in range(len(x)):
        x[i] = x[i]**2

def bar(x):
    for i in range(len(x)):
        x[i] = x[i] - 1

def bar2(x):
    xx = x.copy()
    for i in range(len(x)):
        xx[i] = x[i] - 1
    return xx


if __name__ == '__main__':
    main()

暂时忽略被注释掉的部分,这段程序实现的功能非常简单,main 中产生一个数组,调用 foo 函数,foo 函数又调用 bar 函数,后者使数组中的每一个元素减一,然后返回 foo 函数中,数组的每个元素再次求平方。

上面两个函数中都没有返回值,因为它接受的是数组,类似于 C 语言中的指针传递,直接操作的是原数组。类似的逻辑应该对很多编程语言都是类似的。

然而,如果要考虑通过多进程来将它并行化(比如用 foo 函数来处理非常大的数组),就需要再多一点考虑了。首先因为 Python 中 GIL 的限制,虽然也可以多线程,但速度甚至不如单线程的版本,要有效地实现纯 Python 的并行,(也许是)最佳也是最简单的方案是用多进程。但多进程中各个进程不能共享内存,也就无法像上面那样用指针传递的方式来建立操作数组的方式。

这种情况下,就需要把函数相应地改成显式地返回新数组的形式,也就是上面的 bar2 函数。然而,改写之后,试运行就可以发现,计算的结果不同了。比如x = [1, 2, 3, 4, 5]的输入,得到的结果应该是[0, 1, 4, 9, 16],但实际并非如此。更奇怪的是,监测 foo 函数,发现在函数内部的结果是正确的。这说明是 foo 函数没有正确地操作原输入数组。

想到这里,问题解决了一半。真正的原因是于x = bar2(x)这一行,等号左侧虽然同样用了 x 的变量名,但由于返回了一个新的数组,也就是说开辟了一块新的内存,使得函数后面操作的跟传入的并不是同一个数组,所以返回值看起来就像没变一样。

找到原因,解决的方法也就简单了,两个办法:

  1. 把所有的指针传递函数都改回显式返回数组的形式。
  2. x = bar2(x)改为x[:] = bar2(x),这样操作的就仍然是原来的数组了。

来源:我的博客

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值