2010-08-11 2 views
0

J'écris un script Perl pour exécuter un type de pipeline. Je commence par lire un fichier JSON avec un tas de paramètres. Je fais ensuite un peu de travail - principalement en construisant des structures de données nécessaires plus tard et en appelant des programmes externes qui génèrent des fichiers de sortie auxquels je garde des références. J'utilise habituellement un sous-programme pour chacune de ces étapes. Chaque tel sous-programme écrira généralement des données à un endroit unique qu'aucun autre sous-programme n'écrit (c'est-à-dire une clé spécifique dans un hachage) et lit des données que d'autres sous-programmes peuvent avoir générées. Ces étapes peuvent prendre quelques bonnes minutes si elles sont faites de manière séquentielle, mais la plupart d'entre elles peuvent être exécutées en parallèle avec une simple logique de dépendances que je sais gérer (en utilisant des threads et une file d'attente). Je me demande donc comment je devrais implémenter ceci pour permettre le partage de données entre les threads. Que suggérez-vous le cadre à être? Peut-être utiliser un objet (dont je n'aurai qu'une seule instance) et conserver toutes les données partagées dans $self? Peut-être un script simple (pas d'objets) avec des variables partagées "globales"? ...Conception d'un script perl avec multithreading et partage de données entre threads

Je préférerais évidemment une solution simple et soignée.

Répondre

3

Lecture threads::shared. Par défaut, comme vous le savez peut-être, les variables perl ne sont pas partagées. Mais vous placez l'attribut shared sur eux, et ils le sont.

my %repository: shared; 

Ensuite, si vous souhaitez synchroniser l'accès, le plus simple est de

{ lock(%repository); 
    $repository{JSON_dump} = $json_dump; 
} 
# %respository will be unlocked at the end of scope. 

Cependant, vous pouvez utiliser Thread::Queue, qui sont censés être muss-libre, et faire ainsi:

$repo_queue->enqueue(JSON_dump => $json_dump); 

Ensuite, votre fil de consommateur pourrait simplement:

my ($key, $value) = $repo_queue->dequeue(2); 
$repository{ $key } = $value; 
+0

+1 merci Axeman. est-il nécessaire de verrouiller le référentiel entier quand seulement une partie de celui-ci (par exemple 'repository -> {key}' est changé? –

+0

@David B, oui, malheureusement, il est.Référer à http://search.cpan.org/perldoc? threads :: shared # lock_VARIABLE – Axeman

+0

"Les variables Perl ne sont pas partagées" Pas tout à fait vrai, cela dépend de quelle saveur http://perldoc.perl.org/Thread.html – Hawk

1

Vous pouvez certainement faire cela en Perl, je vous suggère de regarder perldoc threads et perldoc threads::shared, car ces pages de manuel décrivent le mieux les méthodes et les pièges rencontrés lors de l'utilisation de threads en Perl. Ce que je voudrais vraiment vous suggérer d'utiliser, si vous le pouvez, est plutôt un système de gestion de file d'attente tel que Gearman, qui a plusieurs interfaces y compris un module Perl. Cela vous permet de créer autant de «travailleurs» que vous le souhaitez (les sous-traitants effectuant le travail) et de créer un simple «client» qui planifie les tâches appropriées et collationne les résultats, sans avoir besoin d'utiliser des astuces spécifiques aux clés hashref à la tâche ou des choses comme ça.

Cette approche évoluerait également mieux, et vous seriez en mesure d'avoir des clients et des travailleurs (même des gestionnaires) sur des machines différentes, si vous le souhaitez.

D'autres systèmes de file d'attente, tels que TheSchwartz, ne seraient pas indiqués car ils ne disposent pas de la rétroaction/résultat fourni par Gearman. Pour tous les effets, utiliser Gearman de cette façon est à peu près le système filaire que vous avez décrit, sans les tracas et les maux de tête dont tout système basé sur les threads pourrait souffrir: avoir à verrouiller des variables, utiliser des sémaphores, rejoindre des threads.

+0

merci. ce qui me manque est comment suggérez-vous de partager l'information entre les discussions? –

+0

David, consultez http://search.cpan.org/~bradfitz/Gearman/lib/Gearman/Worker.pm – Octoberdan

+0

David, selon l'approche: avec des threads, utilisez des threads :: variables partagées de shared. Avec Gearman, plutôt que de partager des variables, vous pouvez vouloir transmettre des données critiques au thread de travail, comme dans "faire l'opération X avec ceci, ceci et cette autre donnée". Si vous avez besoin de sous-marins différents pour gérer la même donnée, demandez-leur de renvoyer les données fournies. – mfontani

Questions connexes