2012-10-05 2 views
7

이 질문은 두 가지 프로그램 중 하나가 작동하는 것처럼 호기심의 요지입니다.Perl 스레드의 가비지 수집

Image : Magick을 사용하여 많은 사진의 크기를 조정합니다. 약간의 시간을 절약하기 위해 각 사진을 자체 스레드에서 작업하고 동시에 작동하는 스레드의 수를 제한하기 위해 세마포를 사용합니다. 원래는 모든 스레드를 한 번에 실행할 수 있었지만 스크립트는 모든 사진에 대해 3.5GB를 빠르게 할당했으며 (사용 가능한 2GB 만) 스크립트는 모든 스와핑 디스크 때문에 정상보다 5 배 느리게 실행됩니다.

use threads; 
use Thread::Semaphore; 
use Image::Magick; 

my $s = Thread::Semaphore->new(4); 
foreach (@photos) { 
    threads->create(\&launch_thread, $s); 
} 
foreach my $thr (reverse threads->list()) { 
    $thr->join(); 
} 

sub launch_thread { 
    my $s = shift; 
    $s->down(); 
    my $image = Image::Magick->new(); 

    # do memory-heavy work here 

    $s->up(); 
} 

이 빠르게 5백메가바이트을 할당하고, 더욱 필요없이 아주 잘 실행 :

작업은 세마포어 버전 코드는 다음과 같이 보인다. 동시에 80 개 스레드를 시작하고 그들의 대부분을 차단하는 오버 헤드가있을 수 있습니다 경우

내가 궁금해 (. 스레드는 점을 역순으로 연결된다), 그래서 메인 스레드 블록 내 스크립트를 변경 :

my $s = Thread::Semaphore->new(4); 
foreach (@photos) { 
    $s->down(); 
    threads->create(\&launch_thread, $s); 
} 
foreach my $thr (threads->list()) { 
    $thr->join(); 
} 

sub launch_thread { 
    my $s = shift; 
    my $image = Image::Magick->new(); 

    # do memory-heavy work here 

    $s->up(); 
} 

이 버전은 시작되지만 원래 버전에서 사용 된 3.5GB의 공간이 점차 누적됩니다. 한 번에 모든 스레드를 실행하는 것보다 빠르지 만 스레드를 차단하는 것보다 훨씬 느립니다.

내 첫 번째 추측은 join()이 호출 될 때까지 스레드가 사용하는 메모리가 해제되지 않았으며, 차단되는 주 스레드는 모두 할당 될 때까지 스레드가 해제되지 않는다는 것입니다. 그러나 첫 번째 작업 버전에서 스레드는 가드를 더 많거나 적은 임의의 순서로 전달하지만 반대 순서로 결합합니다. 내 추측이 맞다면 실행중인 네 개의 쓰레드보다 더 많은 것이 join() 될 때까지 기다려야한다.이 버전은 더 느려야한다.

왜 두 버전이 이렇게 다른가요?

답변

3

4 개 이상의 스레드를 만들 필요가 없습니다. 하나의 큰 이점은 Perl 인터프리터의 사본 76 개가 더 적음을 의미합니다. 또한 모든 스레드가 거의 같은 시간에 완료되기 때문에 수확 순서가 다소 잘못되었습니다.

use threads; 
use Thread::Queue qw(); 
use Image::Magick qw(); 

use constant NUM_WORKERS => 4; 

sub process { 
    my ($photo) = @_; 
    ... 
} 

{ 
    my $request_q = Thread::Queue->new(); 

    my @threads; 
    for (1..NUM_WORKERS) { 
     push @threads, async { 
      while (my $photo = $request_q->dequeue()) { 
      process($photo); 
      } 
     }; 
    } 

    $request_q->enqueue($_) for @photos; 
    $request_q->enqueue(undef) for 1..NUM_THREADS; 
    $_->join() for @threads; 
} 
+0

다음에 대기열을 시도 할 예정이었습니다. 세마포어의 한 버전을 완벽하게 작동시키는 Perl에서 무슨 일이 일어나고 있는지 궁금 할뿐입니다. – pconley

+0

버전에서 sem을 잠금 해제해야하는 스레드 만 많은 메모리를 사용합니다. 완료되면 수확하면 4 개의 스레드 만 주어진 시간에 많은 메모리를 사용하고 있음을 의미합니다. 마지막에 그것들을 수확하면 결국 80 개의 스레드가 많은 메모리를 사용하게됩니다. – ikegami