Python中指针式传递的函数遇到的问题
来源:互联网 发布:uu黑历史知乎 编辑:程序博客网 时间:2024/05/01 01:03
最近在尝试通过 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]**2def bar(x): for i in range(len(x)): x[i] = x[i] - 1def bar2(x): xx = x.copy() for i in range(len(x)): xx[i] = x[i] - 1 return xxif __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 的变量名,但由于返回了一个新的数组,也就是说开辟了一块新的内存,使得函数后面操作的跟传入的并不是同一个数组,所以返回值看起来就像没变一样。
找到原因,解决的方法也就简单了,两个办法:
- 把所有的指针传递函数都改回显式返回数组的形式。
- 把
x = bar2(x)
改为x[:] = bar2(x)
,这样操作的就仍然是原来的数组了。
来源:我的博客
- Python中指针式传递的函数遇到的问题
- 函数指针的传递问题
- 指针值传递所遇到的问题
- 问题:向函数中传递指针和传递指针的引用的区别
- C函数的指针传递问题
- 函数指针参数的传递问题
- 函数指针参数的传递问题
- 指针作为函数参数传递的问题
- 拷贝构造函数遇到指针的问题
- 【C/C++】函数中指针的传递
- cocos2dx中函数指针传递的方法
- 对函数中指针传递的理解
- 函数指针的传递
- 指针传递遇到的问题--内存角度分析
- 函数参数的传递问题(指针的指针)
- 函数参数的传递问题(指针的指针)(转)
- 函数参数的传递问题(指针的指针)
- 函数参数的传递问题(指针的指针)(转)
- 20151118 parameter
- UVa 1599 Ideal Path
- 解决在onCreate()过程中获取View的width和Height为0的4种方法
- NodeJs 安全
- 数据库 select @@identity说明
- Python中指针式传递的函数遇到的问题
- Android性能测试之概述(一)
- 信号处理国际会议排名
- webservice第一天
- TCP的那些事
- 查找算法总结
- (4.3)uboot详解——异常和异常向量
- ListView嵌套GridView显示不全解决方法
- 【ZJOI2009】狼和羊的故事