J'écris un décompresseur multithread à Python. Chaque fil doit accéder à une partie différente du fichier d'entrée.
Note 1: Il n'est pas possible de charger le fichier entier, car il varie de 15 Go à 200 Go; Je n'utilise pas de multithreading pour accélérer la lecture de données, mais une décompression des données, je veux simplement vous assurer que la lecture des données ne ralentit pas la décompression. P>
Note 2: Le gil n'est pas un problème, ici, comme La fonction principale du décompresseur est une extension C et appelle py_allow_threads, de sorte que la GIL soit libérée pendant la décompression. La deuxième décompression de la deuxième étape utilise un problème qui est également sans gaine. P>
1) J'ai supposé que cela ne fonctionnerait pas simplement à partager un objet de décompresseur (qui enveloppe essentiellement un objet de fichier), car si vous appelle les appels suivants: : P>
seekandread(from_where, length)
Ajouter quelque chose comme p>
decompressor.seek(x) decompressor.read(1024)
Créez un thread qui attend les demandes de lecture et les exécute dans le bon ordre. P> li> ul>
Donc, je manque une solution évidente? Existe-t-il une différence de performance significative entre ces méthodes? P>
merci p> p>
3 Réponses :
Vous voudrez peut-être utiliser le Leader / suiveur motif si vous ne font pas cela déjà.
Le thread leader saura quels segments sont déjà manipulés et qui ne sont pas et s'attribueront avec le prochain segment non transformé, puis devenez un suiveur, laissant le leadership au prochain fil disponible dans la piscine. P>
Merci, je vais examiner cela.
CPPHON a gil que plusieurs threads n'augmentent pas les performances des tâches liées à la CPU. P>
Si le problème n'est pas io-lié (Disk fournit / stocke des données plus rapidement que la CPU le décompresse), vous pouvez utiliser Module multiprofessionnel : Chaque processus ouvre le fichier et décompresse une plage d'octets donnée. P>
La fonction principale du décompresseur est une extension C et appelle py_allow_threads, de sorte que la GIL soit libérée pendant la décompression. La décompression de la deuxième étape utilise un problème qui est également sans gaine. J'ai déjà mesuré une bonne vitesse.
(Peut-être que cette clarification - à propos de vous avait «pris soin» de Gil - pourrait également aller dans le corps principal de la question)
Vous pouvez utiliser MMAP. Voir MMAP () vs. Blocs de lecture P>
Comme Tim Cooper note, le MMAP est une bonne idée lorsque vous avez un accès aléatoire (les threads multiples le feraient semblant de l'avoir), et ils pourraient partager les mêmes pages physiques. P>
Cela semble excellent! J'ai examiné la documentation Python pour le MMAP, mais je n'ai pas pu trouver une référence sur la sécurité thread-sécurité. Si 2 threads font quelque chose comme A = MappedFile [x: y] en même temps, cela va-t-il fonctionner comme prévu?
Pour me répondre, il semble que la notation de la tranche de python MMAP soit réellement threadsafe. J'ai créé un programme de test qui accède à différentes parties d'un fichier mmpped à partir de différents threads et vérifie le résultat. Il passe le test si j'utilise la notation de la tranche, elle échoue si j'utilise la recherche / lecture. Je dois encore vérifier la performance, cependant.
@Alberto: Cela me semble que tout segment donné qui est déjà traité devrait être protégé par au moins un mutex, sinon un sémaphore conditionnel de lancement. Par un sémaphore conditionnel de lancement, je veux dire un sémaphore qui n'attend pas si la condition de pré-entrée n'est pas remplie tant que cela ne sera pas atteint d'une exception. C'est un hybride entre un sémaphore et une Gaurd. Vous voudrez peut-être lancer uniquement lorsque la condition B n'est pas remplie et attendez si la condition A est remplie.
@Alberto: Vous avez besoin d'un mécanisme de verrouillage qui divisera le segment en deux segments lors de l'ouverture d'un nouveau fil sur un segment. Par exemple. Un fil se lit de 0 à 1024 et un nouveau thread est créé et est également attribué à 0 - 1024. Le premier thread a déjà traité les 100 premiers octets afin que vous puissiez diviser le travail sur le deuxième fil. Utilisez ceci uniquement si vous avez vraiment besoin d'optimiser. Je peux laisser une autre réponse avec un algorithme plus détaillé si vous le souhaitez.
@Le_Drow: Je ne suis pas sûr d'avoir compris: Voulez-vous que le verrouillage n'aurait été nécessaire que si deux threads accédaient à la même gamme et ne sont pas nécessaires? Si tel est le cas, il n'y a pas de problème, car le code est écrit de manière à ce qu'il soit impossible pour deux threads de demander les mêmes données: chaque thread est attribué une liste unique de gammes à traiter. Merci
@Alberto: Oui, je le pense. Mais je veux aussi dire que deux threads peuvent être attribués aux mêmes données, ils ne seront attribués qu'à une partie de celui-ci.
OK, j'ai mis en place les deux possibilités et avec la performance du MMAP est plus ou moins identique, mais avec le bonus supplémentaire d'un seul objet de fichier. Je pense que c'est la meilleure solution.
La lecture d'un fichier sur une mode multithread ralentit réellement le processus lorsque vous avez un disque dur. L'aiguille doit sauter d'un endroit à un autre au lieu de travailler de manière itérative. Vous devez charger le fichier avant de le traiter.
Il n'est pas possible de charger le fichier entier, car il varie de 15 Go à 200 Go; Je n'utilise pas de multithreading pour accélérer la lecture de données, mais la décompression des données, je voulais juste que la lecture de données ne ralentit pas la décompression.
Bien sûr, cela peut ou non s'appliquer aux SSDS. Je n'ai aucune idée du sujet cependant. Vous ne devriez pas relâcher sur le matériel pour le faire. Une fois que les SSD sont suffisamment courants, les E / S d'une manière multiples peuvent être efficaces.
Pourriez-vous s'il vous plaît clarifier cela dans votre question?
OK, j'ai ajouté une note