Какой ресурс numpy "блокирует" между процессами? - PullRequest
0 голосов
/ 19 сентября 2018

Итак, друг заметил кое-что любопытное в 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 с.

Обратите внимание, что это также происходит при запуске кода Python с собственным модулем multiprocessing в Pool.Это, однако, не происходит, если вы делаете что-то, что не связано с какими-то конкретными функциями, такими как:

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-основной процессор.Я запомнил это, это не проблема.Во время одной части процесса один процессор находится на 100%, остальные бездействуют.Во время двухпроцессной части две находятся на 100%, остальная часть простаивает (согласно htop).Я понимаю, что numpy запускает библиотеки ATLAS, LAPACK и BLAS в фоновом режиме, которые не являются Python (на самом деле это чистый C или Fortran).Они могут использовать параллельные методы.Мой вопрос здесь, почему это не проявляется в загрузке процессора?

1 Ответ

0 голосов
/ 19 сентября 2018

Numpy не ограничен GIL так, как ядро ​​Python.Это связано с тем, что numpy хранит массив только как объект Python.Сами фактические данные хранятся в виде «примитивных» типов, определенных в C. По этой же причине итерация по массивному массиву происходит намного медленнее, чем итерация по списку Python.Массив numpy должен создавать объект Python для каждого получаемого им значения, в то время как список Python уже содержит объекты Python.

Поскольку GIL не мешает numpy, он может использовать поточные математические библиотеки, где они доступны.Иными словами, параллельные процессы выполнялись дольше, потому что каждый процесс уже максимизировал вашу машину, и поэтому оба процесса конкурировали за одни и те же ресурсы.

Посмотрите на вывод и посмотрите, что доступно в вашеммашина (будьте осторожны, она довольно многословна).

import numpy.distutils.system_info as sysinfo
sysinfo.show_all()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...