Article View: pl.comp.lang.perl
Article #51720Re: Thread::Queue a pusty hash na wyjsciu
From: Vava
Date: Wed, 23 Dec 2009 20:31
Date: Wed, 23 Dec 2009 20:31
129 lines
4221 bytes
4221 bytes
Dnia 23-12-2009 o 17:40:36 Krzysztof Lewicki <menth0l@remove.this.o2.pl>
napisał(a):
> Potrzebuje użyć wątków perlowych i natrafiłem na pewien problem.
> Napisałem
> sobie taki oto przykładowy fragment kodu:
>
> my $queue = Thread::Queue->new();
> my $t1 = threads->create(\&test_reader);
> my $t2 = threads->create(\&test_writer);
>
> $t2->join();
>
> sub test_writer
> {
> while (1)
> {
> sleep 1;
> my %t = (1 => "A", 2 => "B")
> $queue->enqueue(share(%t));
Uwspólnianie zmiennych lokalnych najkrótszą drogą do wycieków pamięci.
Owszem, w dokumentacji do Thread::Queue piszą o sharowaniu haszy przed
kolejkowaniem w celu uniknięcia klonowania, ale dotyczy to zmiennych
globalnych...
Tutaj jest problem, bo robienie takich zmiennych globalnych, to się samemu
prosimy o problemy. Nie w tym testowym przypadku, ale jak więcej wątków ma
pisać do tej kolejki, to bez mutexów będziemy sobie robić kuku.
Więc w zastosowaniach, gdzie prędkość nie jest sprawą kluczową pozwólmy,
by Thread::Queue klonował sobie hasza.
W bardziej wymagających wydajnościowo zastosowaniach, lub przy bardziej
złożonych strukturach danych przekazujmy tylko zwykłe skalary,
serializując dane - jest sporo modułów do tego.
Natomiast to, co powodowało problem, to jest fakt, że Thread::Queue
przekazuje tylko dane skalarne, czyli nie hasze, a referencje do nich...
Czyli pomijając zastrzeżenia wyżej, to powinno wyglądać raczej tak:
my %t : shared = (1 => "A", 2 => "B")
$queue->enqueue(\%t);
Jak używasz czegoś bardziej złożonego niż struktury proste, to użyj
czegokolwiek do serializacji, albo używaj Thread::Queue::Any.
> }
> }
>
> sub test_reader
> {
> threads->detach();
Jak się odczepiasz(detach), to po co się potem przyczepiasz (join)? To nie
zadziała i skrypt przestanie działać w momencie zakończenia się pierwszego
wątku - drugi zostanie zabity mimo tego, że coś jest w kolejce.
> while (my $ref= $queue->dequeue())
Źle - wyjdzie Ci z pętli jak tylko kolejka stanie się pusta, w szczególnym
przypadku, gdy drugi wątek zacznie działać przed tym, nim pierwszy skończy
pierwszego sleepa, to w ogóle nic nie zrobi.
Lepiej pętlę utrzymywać na jakiejś kontrolowanej z zewnątrz zmiennej
współdzielonej, a w niej zrobić drugą opartą na $queue->pending, a wyjadać
z niej wersją nieblokującą (dequeue_nb)
> {
> my %hash = %{$ref}; # wyswietla np. HASH(0x1110970)
> print %hash; # tu juz nic nie wyswietla
> }
> }
Ja bym to zrobił jakoś tak:
#!/usr/bin/perl
use strict;
use threads;
use threads::shared;
use Thread::Queue;
use Data::Dumper;
my $queue = Thread::Queue->new();
my $QUIT : shared = 0;
my $t1 = threads->create(\&test_reader);
my $t2 = threads->create(\&test_writer);
for my $th (threads->list()) {
$th->join;
}
sub test_writer {
my $max = 10;
while (!$QUIT) {
sleep 1;
my %t = (1 => "A", 2 => "B");
$queue->enqueue(\%t);
if (--$max <= 0) {
lock $QUIT;
sleep 5; # by zdążyło wyjść z ew. sleepa z test_reader
$QUIT = 1;
}
threads->yield();
}
}
sub test_reader {
while(!$QUIT) {
while ($queue->pending()){
my $ref = $queue->dequeue_nb;
print Dumper $ref;
}
threads->yield();
}
}
Pozdrawiam
--
Vava
Wawrzyniec Żurowski
Victoria vale, et ubique es, suaviter sternutas
Technical Details
Message-ID:
<op.u5eq920vxt9k2g@ubik>Path:
mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.gazeta.pl!not-for-mailReferences:
<hgth64$21l6$1@news.mm.pl>Show Full Headers
Complete Article Headers
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.gazeta.pl!not-for-mail From: Vava <vava.jedenaste.nie.spamuj@plusnet.pl> Newsgroups: pl.comp.lang.perl Subject: Re: Thread::Queue a pusty hash na wyjsciu Date: Wed, 23 Dec 2009 21:31:04 +0100 Organization: Vava Lines: 129 Message-ID: <op.u5eq920vxt9k2g@ubik> References: <hgth64$21l6$1@news.mm.pl> NNTP-Posting-Host: aate28.neoplus.adsl.tpnet.pl Mime-Version: 1.0 X-Trace: inews.gazeta.pl 1261600266 22952 83.5.242.28 (23 Dec 2009 20:31:06 GMT) X-Complaints-To: usenet@agora.pl NNTP-Posting-Date: Wed, 23 Dec 2009 20:31:06 +0000 (UTC) X-User: rosomakolak User-Agent: Opera Mail/10.10 (Win32) Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit