【问题标题】:What resource does numpy "lock" across processes?numpy 跨进程“锁定”什么资源?
【发布时间】:2018-09-19 13:05:23
【问题描述】:

所以一位朋友注意到了对numpy 的一些好奇。这是一个最小的示例,它首先串行运行相同的脚本,而不是两个实例在各自的进程中并行运行:

#!/bin/bash
# This is runner.sh

fl=/tmp/$(mktemp test_XXXXX.py)
trap "rm -fv '$fl'" EXIT
cat - > "$fl" <<-'EndOfHereDoc'
#!/usr/bin/env python
import numpy as np
import sys

if __name__ == '__main__':
    if len(sys.argv)>1: print(sys.argv[1] +' start: '+ str(datetime.datetime.now()))
    cube_size=100
    cube=np.zeros((cube_size,cube_size,cube_size))
    cube_ones=np.ones((cube_size,cube_size,cube_size))

    for x in range(10000):
        np.add(cube_ones,cube,out=cube)
    if len(sys.argv)>1: print(sys.argv[1] +' start: '+ str(datetime.datetime.now()))
EndOfHereDoc

echo "Serial"
time python "$fl" 0
echo

echo "Parallel"
time python "$fl" 1&
time python3 "$fl" 2&
wait

rm -fv "$fl"
trap '' EXIT

其输出为:

$ runner.sh 
Serial
0 start: 2018-09-19 15:46:52.540881
0 end: 2018-09-19 15:47:04.592280

real    0m12,105s
user    0m12,084s
sys 0m0,020s

Parallel
1 start: 2018-09-19 15:47:04.665260
2 start: 2018-09-19 15:47:04.780635
2 end: 2018-09-19 15:47:27.053261

real    0m22,480s
user    0m22,448s
sys 0m0,128s
1 end: 2018-09-19 15:47:27.097312

real    0m22,505s
user    0m22,409s
sys 0m0,040s
removed '/tmp/test_zWN0V.py'

没有加速。就好像进程一个接一个地运行。我假设 numpy 只使用一个资源,而另一个进程等待该资源被释放。 但是这里到底发生了什么? GIL 应该只是多线程的问题,而不是多进程的问题,对吧?我觉得特别奇怪,p2 不只是在等待 p1 完成。相反,这两个过程都需要大约 22 秒才能完成。我希望一个人获得资源并在一半的时间内完成。而另一个等到第一个释放它并需要额外的约 12 秒。

请注意,在 Pool 中使用 python 自己的 multiprocessing 模块运行 python 代码时也会发生这种情况。但是,如果您执行不涉及某些特定 numpy 函数的操作,例如:

cube_size=25
cube=[0 for i in range(cube_size**3)]

for x in range(10000):
    cube = [ value + 1 for value in cube]

编辑:

我有一个真正的 4 核 CPU。我一直牢记超线程,这不是这里的问题。在单进程部分,一个 CPU 处于 100%,其余的空闲。在两个进程部分中,两个处于 100%,其余处于空闲状态(根据 htop)。我知道 numpy 在后台运行 ATLAS、LAPACK 和 BLAS 库,它们不是 Python(实际上是纯 C 或 Fortran)。这些可能会利用并行技术。我的问题是,为什么 CPU 利用率没有显示出来?

【问题讨论】:

  • 也许你只有一个单核 CPU?或 RAM 不足 - 尝试使用 /usr/bin/time -l python ... 运行并查看最大工作集。
  • @MarkSetchell 看时序输出。并行进程肯定是并行运行的。这里的问题是 numpy is 已经是多线程的(或者可以是)并且擅长多线程,尽管有 GIL(因为 numpy 所做的大部分事情都不使用解释器)。跨度>
  • @Dunes - 是的,你是对的,谢谢。
  • 仅作记录,我有一个四核 CPU。顺便提一句。为了防止其他人自欺欺人,超线程将显示为比您实际拥有的更多 CPU 内核,并且可以在 100% 的利用率下高效地使用。我的后续问题是,如果 numpy 已经并行运行,为什么在单进程示例中只有一个 100% 的核心,而其余的则空闲?

标签: python performance numpy multiprocessing


【解决方案1】:

Numpy 不像核心 Python 那样受 GIL 限制。这是因为 numpy 仅将数组存储为 Python 对象。实际数据本身存储为 C 中定义的“原始”类型。这也是迭代 numpy 数组比迭代 Python 列表慢得多的原因。 numpy 数组必须为它产生的每个值构建一个 Python 对象,而 Python 列表已经有 Python 对象。

由于 numpy 不受 GIL 的限制,它能够在可用的情况下使用线程数学库。也就是说,您的并行进程需要更长的时间才能运行,因为每个进程都已经用尽了您的机器,因此两个进程都在争夺相同的资源。

看看输出,看看你的机器有什么可用的(注意它很冗长)。

import numpy.distutils.system_info as sysinfo
sysinfo.show_all()

【讨论】:

  • 您似乎对numpy 很了解,也许您愿意看看这个stackoverflow.com/a/52188236/2836621,如果您有时间,请不要担心:-)
  • 我添加了另一个答案。但不确定它真的有多大帮助。这个问题似乎不仅仅涉及 numpy。
  • 嗯...但是在我发布的示例中,当我使用htop 查看我的 cpu 使用率时,我得到一个核心 100% 用于一个进程部分和 两个 对于两个进程正在运行的部分,每个内核都为 100%。如果 numpy 已经在并行运行,它应该显示在 htop 中。
  • “最大化你的机器”不仅仅意味着每秒的 CPU 指令。它也可能意味着每秒 RAM 读/写。您的数组有 1,000,000 个项目 (100^3)。您有两个,默认情况下它们具有 64 位浮点数。 16MB 仅用于单个进程的数据。 i7 CPU 的 L3 高速缓存为 8MB,并在所有处理器之间共享。因此,两个进程都必须经常加载数据并将数据写入 RAM,并且如果另一个进程正在执行读/写,则可能必须等待。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-02
  • 1970-01-01
相关资源
最近更新 更多