Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Общие вопросы > perl+threads


Автор: klem4 26.1.2010, 23:31
Не приходилось до сего дня применять в работе потоки в perl, так что познания мои пока не велики в этом вопросе, есть код, в нем 2 сортировки целых и вещественных списков(по 100 000 элементов), в no_threads сабе они происходят последовательно,  а в threads разбиваются на 2 нити. Скорость первой значительно превышает скорость второй.  Верно ли идет разбиение на потоки ?

Код

sub no_threads
{
    &$sort_int;
    &$sort_real;
}
sub multi_threads
{
    ( new threads(\&$sort_int)  )->join;
    ( new threads(\&$sort_real) )->join;
}


Результат работы:
Код

NO_THREADS|1|stop at Tue Jan 26 23:15:33 2010|full_time= 0.0016
THREADS|2|stop at Tue Jan 26 23:15:33 2010|full_time= 0.2262


Perl мультитредовый, процессоры многоядерные. Linux 32bit. 


Автор: mvsgt 27.1.2010, 00:14
вообще с потоками должно быть быстрее, но результат full_time= 0.0016 и 0.2262 1) какие-то маленькие, 2) различаться должны всё-таки не на два порядка а в два раза. На коротких тестах доля накладных расходов скроет разницу в скорости.

Автор: klem4 27.1.2010, 00:34
Да, цифры подозрительно маленькие, подозреваю в чем причина, завтра проверю.

Автор: DurRandir 27.1.2010, 07:57
Вызов join блокирует текущий поток, заставляю дождаться окончания потока-потомка. Т.е. во 2м варианте у вас выйдет такое же линейное исполнение+накладные расходы на потоки (да, они настолько велики). Правильно так:

push @thr, thread->new();
$_->join() for @thr;

PS: не используйте потоки в perl smile

Автор: klem4 27.1.2010, 18:22
1) По поводу странной скорости. Сабы исправлены из вида

Код

my $sort_int = sub
    {
        sort( @int_array )
    };


в

Код

my $sort_int = sub
    {
        my @sorted = sort( @int_array )
    };


2) По поводу вызова. Все равно удручает результат:

Код

sub multi_threads
{
    my @threads = ( new threads(\&$sort_int), new threads(\&$sort_real) );
    $_->join for ( @threads );
}


Код

NO_THREADS|1|stop at Wed Jan 27 18:21:24 2010|full_time= 0.7261
THREADS|2|stop at Wed Jan 27 18:21:25 2010|full_time= 0.9584


Может в сторону fork покопать.
Спасибо за внимание.

Автор: mvsgt 28.1.2010, 00:52
Когда что-то тестируете, публикуйте полный текст тестовой программы, иначе никакого смысла нет в публичном обсуждении результатов  неизвестно какого процесса. Например, кусок
 my @sorted = sort( @int_array )
это что за @int_array ? как и где оно определено? Но это только один из вопросов, надо видеть весь текст тестов, чтобыы понять что происходит. И вообще, сколько у Вас процессоров?

Автор: klem4 28.1.2010, 01:39
Полный код выглядит так (в модуле Timers сабы для замера времен с использованием Time::HiRes, если надо, приведу и его):

Код

#!/usr/bin/perl
use strict;
use threads;
use lib qw[ /home/lib ];
use Timers;
use constant ARRAY_LENGTH => 100000;

    my @int_array  = map { int rand 1000 } 1..ARRAY_LENGTH;
    my @real_array = map { rand } 1..ARRAY_LENGTH;

    my $sort_int = sub
    {
        my @sorted = sort( @int_array )
    };

    my $sort_real = sub
    {
        my @sorted = sort ( @real_array )
    };


    _start "NO_THREADS", "1";   &no_threads;    _stop "NO_THREADS", "1";
    _start "THREADS", "2";      &multi_threads; _stop "THREADS", "2";

sub no_threads
{
    &$sort_int;
    &$sort_real;
}

sub multi_threads
{
    my @threads = ( new threads(\&$sort_int), new threads(\&$sort_real) );
    $_->join for ( @threads );
}


4 Intel® Xeon® CPU  5110  @ 1.60GHz
cpu cores       : 2

Автор: DurRandir 28.1.2010, 11:13
Вообще, оно ещё быстро отработало. Без особых шуток smile

Как перл создаёт свой "поток"?
1. Нам надо создать поток - создаём его. На текущий момент все данные в памяти - общие.
2. Клонируемся, делая все данные приватными

Теперь, сколько всё это занимает времени?
time perl -e 'ar=map{rand} 0..100000;'
0.15s user 0.01s system 99% cpu 0.157 total

Сколько занимает времени сортировка?
time perl -e 'ar=map{rand} 0..100000; @b=sort @ar'
0.80s user 0.02s system 99% cpu 0.828 total
Чистого времени - 0,65

Сколько занимает времени скопировать данные? Это измерение неточное, я просто померяю сколько занимает пройтись по внутренним структурам данных (что обязательно для копирования, оценка снизу):
time perl -e 'use Devel::Size qw/total_size/; @ar=map{rand} 0..100000; total_size(\@ar)'
0.29s user 0.02s system 89% cpu 0.338 total
Чистого времени - 0.14

Итого, создать 2 массива+отсортировать = 2*(0,15+0,65) = 1.6
Теперь, с потоками. Создать 2 массива, скопировать оба в 1й поток, скопировать оба во 2й поток, отсортировать (учитываем 1 раз, т.к. выполняется одновременно) = 2*0,15+2*2*0.14+0.65=1.51

Это оценка снизу, копирование учитывается не полностью. Выигрыш - в теории, копеечный, в реальности - отрицательный.

Чтобы был выигрыш, время копирования данных должно быть меньше времени обработки. Причём проигрыш во времени копирования накапливается гораздо быстрее, чем выигрыш в обработке. Если вам нужны потоки - не держите в памяти много данных _до_ создания потока. Или же затраты CPU на обработку должны быть значительно больше. Лучше всего, отказаться от потоков вообще smile

PS: как ни странно, но _сначала_ создать потоки, а потом в них с нуля создавать данные - будет быстрее, попробуйте. 2*2*0,15+0,65=1.25

Автор: klem4 28.1.2010, 18:03
Благодарю за столь развернутый ответ. Поэксперементирую еще на досуге. Плюсанул бы, да 100 постов надо.

Автор: shamber 28.1.2010, 23:47
klem4, не расстраивайтесь, уже плюсанули 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)