🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: pl.comp.lang.perl
Article #51720

Re: Thread::Queue a pusty hash na wyjsciu

#51720
From: Vava
Date: Wed, 23 Dec 2009 20:31
129 lines
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-mail
References: <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