Как использовать потоки для замены цикла подпрограммы в perl/pdl

У меня есть очень хорошая подпрограмма Perl, написанная как часть модуля Perl. Не вдаваясь в подробности, он принимает строку и короткий список в качестве аргументов (часто берется из терминала) и выдает значение (прямо сейчас, всегда с плавающей запятой, но это не всегда так).

Прямо сейчас, часть списка моего аргумента принимает два значения, скажем (val1,val2). Я сохраняю вывод моей подпрограммы для сотен различных значений для val1 и val2, используя циклы for. Каждая итерация занимает почти секунду, поэтому весь этот процесс занимает часы.

Недавно я читал о мистическом (для меня) вычислительном инструменте, называемом "многопоточность", который, очевидно, может заменить циклы с невероятно быстрым временем выполнения. У меня были проблемы с пониманием, что это такое и что они делают, но я думаю, что они как-то связаны с параллельными вычислениями (и я хотел бы, чтобы мой модуль был максимально оптимизирован для параллельных процессоров).

Если я сохраню все значения, которые я хотел бы передать в val1 в виде списка, скажем, @val1 и то же самое для val2, как я могу использовать эти "потоки" для выполнения моей подпрограммы для каждой комбинации элементов val1 и val2? Кроме того, было бы полезно узнать, как обобщить эту процедуру для подпрограммы, которая также принимает val3, val4 и т. Д.

2 ответа

Обновить:

Я не использую PDL, поэтому я не знал, что поток в PDL не соответствует в точности понятию потоков, о котором я говорил. Смотрите разделы PDL и подписи:

Сначала мы должны объяснить, что мы подразумеваем под многопоточностью в контексте PDL, тем более что термин "многопоточность" уже имеет особое значение в компьютерной науке, что лишь частично согласуется с его использованием в PDL.

Тем не менее, я думаю, что приведенное ниже объяснение по-прежнему полезно для вас, так как нужно знать, что такое обычные потоки, чтобы понять, чем отличаются потоки PDL.

Вот запись темы в Википедии для фона.

Использование потоков не может сделать вашу программу волшебно быстрее. Если у вас есть несколько процессоров / ядер и если выполняемые вами вычисления можно разделить на независимые фрагменты, использование потоков может позволить вашей программе выполнять более одного вычисления за раз и сократить общее время выполнения.

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

Что касается возможного увеличения производительности, рассмотрим следующую программу:

#!/usr/bin/perl

use strict; use warnings;
use threads;

my ($n) = @ARGV;

my @threads = map { threads->create(\&act_busy) } 1 .. $n;

$_->join for @threads;

sub act_busy {
    for (1 .. 10_000_000) {
        my $x = 2 * 2;
    }
}

На моем двухъядерном ноутбуке под управлением Windows XP:

C: \> время это t.pl 1
Время: истекшее время: 00: 00: 02.375
C: \> время это t.pl 2
Время: прошедшее время: 00: 00: 02.515
C: \> время это t.pl 3
TimeThis: Elapsed Time: 00: 00: 03.734
C: \> время это т.пл 4
TimeThis: Elapsed Time: 00: 00: 04.703
...
C: \> время это t.pl 10
TimeThis:  Elapsed Time:  00:00:11.703

Теперь сравните это с:

#!/usr/bin/perl

use strict; use warnings;

my ($n) = @ARGV;

act_busy() for 1 .. $n;

sub act_busy {
    for (1 .. 10_000_000) {
        my $x = 2 * 2;
    }
}
C: \> время это с.пл 10
Время: истекшее время:  00:00:22.312

Как говорит Синан, «поточность», о которой вы, вероятно, думали, — это «потоки PDL», теперь переименованная (начиная с версии 2.075) в «широковещательную рассылку», чтобы соответствовать общей терминологии (см. документы ). Это позволяет вам заменить что-то вроде этого:

      $x = sequence(5);
$x->set($_, $x->at($_)+2) for 0..$x->dim(0)-1;

именно с этим, поскольку "+=" в основном работает с одной вещью (нульмерным скаляром), поэтому с большим количеством измерений, чем скаляр (например, эта одномерная последовательность), он может "транслировать":

      $x += 2; # does whole ndarray at once

Это также быстрее, потому что в отличие от forцикла, ему не нужно постоянно покидать и снова входить в среду Perl (также известную как «Perl-land»), но он может оставаться в чрезвычайно быстрой «C-land» для выполнения вычислений без накладных расходов.

Мотивация его первоначального названия заключалась в том, что все эти «транслируемые» вычисления независимы и, следовательно, «досадно параллельны», поэтому их можно автоматически распараллеливать. См. документ . Начиная с версии 2.059, PDL по умолчанию устанавливает автоматическую параллельную обработку в зависимости от количества доступных ядер ЦП.

Другие вопросы по тегам