2012-10-23 5 views
4

J'ai une liste (appelée requestRoster) contenant des dictionnaires (demandes appelées). Les éléments du dictionnaire 'requests' sont des choses comme 'requestTime' et 'thisURL'. .: par exemple Comment puis-je créer une structure de données interprocess en Python?

[ 
{'thisURL': 'http://localhost/bikes', 'requestTime': datetime.datetime(2012, 10, 18, 0, 41, 34)}, 
{'thisURL': 'http://localhost/clothing', 'requestTime': datetime.datetime(2012, 10, 18, 0, 41, 35)} 
] 

J'utilise multiprocessing.Process pour frayer un nouveau processus pour émettre chaque demande.

J'aimerais que chaque processus mette à jour le requestRoster en ajoutant un élément 'response' à chaque requête.

Comment est-ce que je peux faire ceci?

J'ai essayé d'utiliser un multiprocessing.Manager() pour créer un manager.list() et un manager.Namespace(). Ni me laisse faire ce que je veux faire, je pense à cause de cela: http://docs.python.org/library/multiprocessing.html#multiprocessing.managers.SyncManager.list

Je pense que je pourrais utiliser un multiprocessing.Lock() pour

  • acquérir un mutex
  • faire une copie le requestRoster à l'intérieur du processus
  • modifier la requestRoster localisée
  • remplacer le fichier de demande « globablised » avec le localisé une
  • libération du mutex

... mais cela semble un peu compliqué et je me demande s'il me manque quelque chose de plus simple. Un rappel asynchrone serait génial.

+0

Est-ce que vos employés ont besoin de lire à partir de la liste ou simplement d'y répondre? De votre description, il semble qu'une simple file d'attente ou même un tuyau connecté entre le répartiteur et chaque travailleur devrait travailler pour repousser vos données de réponse, puis le répartiteur peut être chargé de consigner la réponse à la bonne entrée dans votre historique des appels . –

+0

Ok, une file d'attente. Donc le répartiteur dépêche; le travailleur travaille; le travailleur ajoute un résultat à une file d'attente; le répartiteur considère la file d'attente et supprime les réponses. Quelque chose comme ca? J'aime ça ... la seule chose dont je me méfie, c'est de rendre le répartiteur responsable de quoi que ce soit d'autre que l'envoi, car il est déjà débordé de travail lorsque des centaines de demandes doivent être envoyées simultanément. Je pense qu'il y a de vrais arguments en faveur du processus de travail pour avoir accès à une structure de données «globale» ... et pour que les travailleurs fassent tout le travail, y compris la mise à jour. – dave

+0

Cela se développe sur moi. Je pourrais demander au répartiteur de ne le faire que lorsqu'il aura le temps de le faire, mais concentrez-vous sur l'envoi la plupart du temps. Merci pour votre contribution. – dave

Répondre

2

Il est préférable d'éviter les structures de mémoire partagée, si vous le pouvez. Ici, il n'y a aucune raison pour que les processus écrivent eux-mêmes dans la liste des dicts - au lieu de cela, vous pouvez rendre le processus principal responsable et extraire uniquement l'URL vers les processus.

J'aime concurrent.futures.<Process|Thread>PoolExecutor pour ce genre de chose.

+0

Merci pour votre contribution, mais je suis sur Python 2.7.3, donc je ne pense pas que je peux encore utiliser concurrencut.futures (bien que cela semble bon). Je pense qu'il vaudrait mieux que les processus enfants (ou tout ce que vous voulez les appeler) écrivent sur la liste des dicts parce que le processus principal est déjà surchargé de travail - par exemple, quand des centaines de requêtes doivent être envoyées 'simultanément' . – dave

+0

Il y a un backport Python 2.x que je peux confirmer fonctionne! – katrielalex

0

Je pense que cette approche devrait travailler pour vous:

Dispatcher:

create logger_queue 
create logger process, initialize with logger_queue 
for each request 
    create worker_pipe 
    create worker process, initialize with send end of worker_pipe 
    push receive end of worker_pipe over logger_queue 

Travailleur:

make request 
push response over connection 

Enregistreur:

while True 
    for connection on logger_queue 
     create new element in logging list 
     link connection to new logging list element 
    for each open connection 
     poll for message 
     if message 
      store message to log 
      close connection 

Le processus d'enregistreur peut également être fonctionnement Quelles que soient les routines de sortie souhaitées, vous n'avez même pas à vous préoccuper de la lecture d'un autre processus dans l'ensemble de données consigné. Notez que la connexion ci-dessus fait référence à multiprocessing.Connection.

+0

Entrée très appréciée, mais massivement complexe considérant que je veux juste globaliser une structure de données. Je ne veux pas vraiment faire des files d'attente, des tuyaux et des enregistreurs (plus de problèmes) Je veux juste que les travailleurs puissent mettre à jour les données dans le processus principal ... (merci encore pour votre contribution, cela est apprécié) – dave

+0

sont très complexes et ont beaucoup de frais généraux et d'embûches. Si vous pouvez les éviter, vous devriez probablement. Si vous voulez simplement tout faire dans le processus principal, placez la logique du logger dans le répartiteur et découpez la file d'attente. Je l'ai cassé de cette façon parce que vous avez dit que vous vouliez que le répartiteur soit maigre. –

0

J'ai réussi à le faire en utilisant le threading au lieu du multitraitement. Parce que les travailleurs sont dans le même processus que le répartiteur, ils peuvent mettre à jour le requestRoster.

+0

Threading sera probablement bien pour vous puisque vos travailleurs sont liés à l'E/S, mais sachez que si vous vous lancez dans des problèmes de performance liés à l'UC, le GIL vous forcera à passer en multiprocessus. –

+0

En effet. Et merci encore pour vos commentaires. – dave

Questions connexes