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


Автор: StealtH 3.9.2007, 09:57
Есть код:

Код


#!/usr/bin/perl -w

use strict;
use threads;
use threads::shared;
use Fcntl qw(:DEFAULT :flock);

my $max_threads = 20;
my $worksthreads : shared = 0;

open FILE, 'words';
chomp(my @words = <FILE>);

my @threads;

    for (my $j = 0; $j <$#words; $j++){

        if ($worksthreads <= $max_threads){

            $threads[$worksthreads++] =  threads->create(\&threads_sub, $words[$j]);
        } else {
            print $worksthreads . " thread work\n";
            sleep 1;

            while(my $th = shift @threads){

                print $th->tid, "\n";
                $th->join;
                $worksthreads--;
                $th = undef;

            }
        }
    }



sub thread_sub{


    my $word = shift;
    my $tid = shift;

    my $var = 0;

    for (0..450){

        $var += $_.$word;

    }
    sleep 1;
    $worksthreads--;
    print $filename, " => $worksthreads\n";
    undef $tid;
    return 1;
}




Суть проблемы такова, что потоки не умирают должным образом и остаются в памяти, с учетом того, что в среднем каждый поток весит примерно 10 метров, то на 300-350 итерации цикла на сервере не остается оперативки, а 400 итераций - это даже не 1% файла. 

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

OS - ASPLinux 10
Код

bash-3.00# perl -v

This is perl, v5.8.5 built for i386-linux-thread-multi

Copyright 1987-2004, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using `man perl' or `perldoc perl'.  If you have access to the
Internet, point your browser at http://www.perl.com/, the Perl Home Page.

Автор: Bulat 5.9.2007, 08:24
StealtH, с многопоточностью работаю через fork, но думаю что в этом моенте разницы не будет. Для того чтобы убивать зомби использую

Код

use POSIX 'WNOHANG';

.....

$SIG{CHLD} = sub {
    while ( ( my $kid = waitpid( -1, WNOHANG ) ) > 0 ) {
        warn "Reaped child with PID $kid\n";
    }
};


Автор: fray 5.9.2007, 13:04
Работать с тредами нужно очень аккуратно. Так как они капризные и могут возникать разные "эффекты" с памятью 
сделай хотяб так...

Код

my @threads;

for (1..THREADS) {
    my ($tid) = threads->create(\&child);
    if ( $tid ) {
        push @threads, $tid;
    } else {
        warn "Cannot create thread number $_";
        last;
    }
}
$_->join for @threads;

вот так !
потом зачем передавать $words[$j] ведь на то они и треды чтобы находится в одной области памяти к родителю сделай так чтобы, элемены массива выбирались  прям в сабе, хотя конечно мож я забыл что ты спрашивал. 

Автор: StealtH 6.9.2007, 22:51
Bulat, помогло, но не совсем, памяти стали потоки съедать меньше, но все же остается момент когда они ее поедают, постепенно объем занимаемой памяти растет :(


fray, насчет юзать переменные прямо в сабе - хорошая мысль, попробовал, мне понравилось  smile 

Автор: Bulat 9.9.2007, 11:19
Цитата(StealtH @  6.9.2007,  22:51 Найти цитируемый пост)
но все же остается момент когда они ее поедают, постепенно объем занимаемой памяти растет

Все зависит от того чем ты занимаешься в дочерних процессах. Лично у меня дочерние процессы съедали не более 11,5 Mb. Но у меня шла работа с большими скалярами, объемом до нескольких сотен килобайт, может даже 1 мегабайт. Так вот при выполнении определенных операций, перл использует дополнительную память, которую впсоледствии не высвобождает. Пришлось переделать некоторые места кода, теперь несколько дочерних процессов съедают от 7,5 до 10,5 мегабайт. Немного для одного, но в целом не плохо.

Тут уже как бы сказать вопрос не к многопоточности относится, а немного к иному smile. Кстати была еще одна проблема, когда дочерние процы висели, т.е. рандомное время работали хорошо. а потом начниали подвисат загружая процессор, причем очень серьезно, могли висеть по долгу, при этом выполняли что-то. Думал, что может есть какая особенность, но для начала передала один фрагмент кода, и висеть перестали smile

Автор: StealtH 15.9.2007, 20:14
Bulat,  в "детях" происходит банальное скачивание контента, далее удаление тэгов и индексация по уникальным словам с подсчетом повторений в слов в тексте, т.е. прога по сути своей поисковый паук, была проблема с памятью, в среднем поток "весил" порядка 10-12 метров, но потом я отказался от LWP и переписал все на сокеты, в самой подпрограмме, из которой делается поток все переменные уничтожаются по мере их использования, старался оптимизировал код как мог, но все-таки остается проблема с зависшими процессами, количество которых накапливается, и соответственно количество свободной памяти уменьшается. 
Вот собственно и сама проблема, решения пока найти не могу.

Автор: Bulat 1.10.2007, 14:51
Цитата(StealtH @  15.9.2007,  20:14 Найти цитируемый пост)
в среднем поток "весил" порядка 10-12 метров

У меня подобное было, но после оптимизации кода, я снизил до 9-10, немного конечно, но пара мегобайт умноженные хотя бы на 10 дочерних процессов уже ~20. 

Цитата(StealtH @  15.9.2007,  20:14 Найти цитируемый пост)
отказался от LWP 

я не стал отказыватся, видел как работают и на простых сокетах и с ЛВП, как-то не показалось, что настолько уж лучше smile

Цитата(StealtH @  15.9.2007,  20:14 Найти цитируемый пост)
но все-таки остается проблема с зависшими процессами

значит что-то не так с твоим кодом, после вышеприведенного куска кода, отработавшие свое дочерние процы не должны зависать. У меня код был написан так, что одновременно могли работать не более 10 дочерних процессов. Возможно, где-то у тебя происходит, что дочерние потоки порождают новые??? Не знаю, если ты нормально убиваешь дочерние процы, после этого еще и нормально убиваешь зомби, зависать не должны smile

Автор: G0rinich 2.10.2007, 10:43
http://poe.perl.org/ спасет мир smile
Это если работаете с http://gorinich.net/posts/12.

Добавлено через 7 минут и 37 секунд
http://forum.vingrad.ru/index.php?showtopic=124167&view=findpost&p=1081025 можно посмотреть пример хорошего такого паучка. Код конечно приведен для примера. Оптимизированный такой скрипт на самописных "боевых" компонентах способен выжимать 100 - 1К запросов в секунду ;)

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