Pie*_*ert 10 python ipython ipython-parallel
我正在使用 ipyparallel 模块来加速所有列表的比较,但我遇到了内存消耗巨大的问题。
这是我正在运行的脚本的简化版本:
从 SLURM 脚本启动集群并运行 python 脚本
ipcluster start -n 20 --cluster-id="cluster-id-dummy" &
sleep 60
ipython /global/home/users/pierrj/git/python/dummy_ipython_parallel.py
ipcluster stop --cluster-id="cluster-id-dummy"
Run Code Online (Sandbox Code Playgroud)
在 python 中,为简化示例创建两个列表列表
import ipyparallel as ipp
from itertools import compress
list1 = [ [i, i, i] for i in range(4000000)]
list2 = [ [i, i, i] for i in range(2000000, 6000000)]
Run Code Online (Sandbox Code Playgroud)
然后定义我的列表比较函数:
def loop(item):
for i in range(len(list2)):
if list2[i][0] == item[0]:
return True
return False
Run Code Online (Sandbox Code Playgroud)
然后连接到我的 ipython 引擎,将 list2 推送到每个引擎并映射我的函数:
rc = ipp.Client(profile='default', cluster_id = "cluster-id-dummy")
dview = rc[:]
dview.block = True
lview = rc.load_balanced_view()
lview.block = True
mydict = dict(list2 = list2)
dview.push(mydict)
trueorfalse = list(lview.map(loop, list1))
Run Code Online (Sandbox Code Playgroud)
如前所述,我使用 SLURM 在集群上运行它,并从 sacct 命令获取内存使用情况。这是我在每个步骤中获得的内存使用情况:
只需创建两个列表:1.4 Gb 创建两个列表并将它们推送到 20 个引擎:22.5 Gb 一切:62.5 Gb++(这是我遇到 OUT_OF_MEMORY 故障的地方)
从运行作业时在节点上运行 htop 来看,内存使用量似乎随着时间的推移缓慢上升,直到达到最大内存并失败。
我梳理了之前的线程并实现了一些建议的解决方案,但没有成功
我尝试用每个循环清除视图:
def loop(item):
lview.results.clear()
for i in range(len(list2)):
if list2[i][0] == item[0]:
return True
return False
Run Code Online (Sandbox Code Playgroud)
我尝试用每个循环清除客户端:
def loop(item):
rc.purge_everything()
for i in range(len(list2)):
if list2[i][0] == item[0]:
return True
return False
Run Code Online (Sandbox Code Playgroud)
我尝试将 --nodb 和 --sqlitedb 标志与 ipcontroller 一起使用,并像这样启动我的集群:
ipcontroller --profile=pierrj --nodb --cluster-id='cluster-id-dummy' &
sleep 60
for (( i = 0 ; i < 20; i++)); do ipengine --profile=pierrj --cluster-id='cluster-id-dummy' & done
sleep 60
ipython /global/home/users/pierrj/git/python/dummy_ipython_parallel.py
ipcluster stop --cluster-id="cluster-id-dummy" --profile=pierrj
Run Code Online (Sandbox Code Playgroud)
不幸的是,这些都没有帮助,并且导致了完全相同的内存不足错误。
任何建议或帮助将不胜感激!
小智 2
环顾四周,似乎有很多人抱怨 LoadBalancedViews 的内存效率非常低,并且我无法找到任何关于如何解决此问题的有用建议,例如。
\n但是,我怀疑鉴于您的示例,这不是开始的地方。我假设您的示例是您的代码的合理近似。如果您的代码正在与数百万个数据点进行列表比较,我建议您使用 numpy 之类的东西来执行计算,而不是在 python 中迭代。
\n如果您重构算法以使用 numpy 向量运算,它将比索引到列表并在 python 中执行计算快得多。numpy 是一个 C 库,在库内完成的计算将受益于编译时优化。此外,在阵列上执行操作还受益于处理器预测缓存(您的 CPU 希望您向前使用相邻内存并预加载它;如果您零散地访问数据,您可能会失去这种好处)。
\n我对你的例子做了一个非常快速的修改来证明这一点。此示例将您的loop计算与同一问题的非常 na\xc3\xafve numpy 实现进行比较。python 循环方法在处理少量条目时具有竞争力,但随着您处理的条目数量的增加,它的速度很快就会提高 100 倍。我怀疑查看数据结构的方式将超过通过并行化获得的性能增益。
请注意,我选择了分布中间的匹配值;性能差异显然取决于分布。
\nimport numpy as np\nimport time\n\ndef loop(item, list2):\n for i in range(len(list2)):\n if list2[i][0] == item[0]:\n return True\n return False\n\ndef run_comparison(scale):\n list2 = [ [i, i, i] for i in range(4 * scale)]\n arr2 = np.array([i for i in range(4 * scale)])\n\n test_value = (2 * scale)\n np_start = time.perf_counter()\n res1 = test_value in arr2\n np_end = time.perf_counter()\n np_time = np_end - np_start\n\n loop_start = time.perf_counter()\n res2 = loop((test_value, 0, 0), list2)\n loop_end = time.perf_counter()\n loop_time = loop_end - loop_start\n\n assert res1 == res2\n\n return (scale, loop_time / np_time)\n\nprint([run_comparison(v) for v in [100, 1000, 10000, 100000, 1000000, 10000000]])\nRun Code Online (Sandbox Code Playgroud)\n返回:
\n[\n (100, 1.0315526939407524),\n (1000, 19.066806587378263),\n (10000, 91.16463510672537),\n (100000, 83.63064249916434),\n (1000000, 114.37531283123414),\n (10000000, 121.09979997458508)\n]\nRun Code Online (Sandbox Code Playgroud)\n