Затраты на ProcessPoolExecutor ?? параллельная обработка занимает больше времени, чем один процесс для работы с матрицами большого размера - PullRequest
0 голосов
/ 03 октября 2019

Мой код на питоне содержит матрицу и вектор большого размера (более 2 ^ (десятки ...)). Чтобы сократить время вычислений, я применил параллельную обработку, разделив матрицу, соответствующую количеству ядер процессора. Я использовал concurrent.futures.ProcessPoolExecutor. Моя проблема в том, что параллельная обработка занимает гораздо больше времени, чем однократная обработка.

Вот мой код.

  1. однопроцессный код.
self._vector = np.dot(matrix, self._vector)
код параллельной обработки.
    each_worker_coverage = int(self._dimension/self.workers)
         args = []
         for i in range(self.workers):
             if (i+1)*each_worker_coverage < self._dimension:
                 arg = [i, gate[i*each_worker_coverage:(i+1)*each_worker_coverage], self._vector]
             else:
                 arg = [i, gate[i*each_worker_coverage:self._dimension], self._vector]
             args.append(arg)
         pool = futures.ProcessPoolExecutor(self.workers)
         results = list(pool.map(innerproduct, args, chunksize=1))
         for result in results:
             if (result[0]+1)*each_worker_coverage < self._dimension:
                 self._vector[result[0]*each_worker_coverage:(result[0]+1)*each_worker_coverage] = result[1]
             else:
                 self._vector[result[0]*each_worker_coverage:self._dimension] = result[1]

Функция внутреннего продукта, вызываемая параллельно, выглядит следующим образом.

def innerproduct(args):
    answer = np.dot(args[1], args[2])
    return args[0], answer
    ```

For a 2^14 x 2^14 matrix and a 2^14 vector, the single process code takes only 0.05 seconds, but the parallel processing code takes 6.2 seconds.
I also checked the time with the `innerproduct` method, and it only takes 0.02~0.03 sec.
I don't understand this situation.
Why does the parallel processing (multi-processing not multi-threading) take more time?



1 Ответ

0 голосов
/ 03 октября 2019

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

Такто, что следует, мое лучшее предположение. Чтобы многопроцессорная обработка работала, родительский процесс должен передать данные, использованные в вычислениях, рабочим процессам. Время, которое требуется, зависит от объема данных. Перенос матрицы 2 ^ 14 x 2 ^ 14, вероятно, займет значительное время. Я подозреваю, что эта передача данных занимает дополнительное время.

Если вы используете операционную систему, которая использует fork startmethod для multiprocessing / concurrent.futures, , есть способвокруг этой передачи данных . Этими операционными системами являются, например, Linux, * BSD и macOS (но не ms-windows).

В вышеупомянутых операционных системах многопроцессорная обработка использует системный вызов fork для создания своих рабочих. Этот системный вызов создает копию родительского процесса в качестве дочернего процесса. Поэтому, если вы создадите векторы и матрицы до , создав ProcessPoolExecutor, рабочие унаследуют эти данные. Это не очень дорогая или трудоемкая операция, потому что все эти ОС используют копирование при записи для управления страницами памяти. Пока исходная матрица не изменена, все программы, использующие ее, читают с одних и тех же страниц памяти. Это наследование данных означает, что вам не нужно явно передавать данные работнику. Вам просто нужно передать небольшую структуру данных, в которой указано, с какими диапазонами индексов должен работать работник.

К сожалению, из-за технических ограничений платформы это не работает в ms-windows. То, что вы могли бы сделать в ms-windows, - это сохранить исходные двоичные файлы с матричной и векторной памятью перед созданием Executor. Если вы пометите эти сопоставления именем, рабочие процессы должны иметь возможность отображать те же данные в свою память без необходимости их переноса. Я думаю, можно ли поручить numpy использовать такой необработанный двоичный массив без его воссоздания.

На обеих платформах вы можете использовать одну и ту же технику для «отправки данных» родительскому процессу;сохраните данные в общей памяти и верните имя файла или тэг родительскому процессу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...