Dans mon programme, je simule un système N-Corps pour un grand nombre d'itérations. Pour chaque itération, je produise un ensemble de coordonnées 6n que j'ai besoin d'ajouter à un fichier, puis à utiliser pour exécuter la prochaine itération. Le code est écrit en C ++ et utilise actuellement Je ne suis pas un expert dans ce domaine, mais j'aimerais améliorer cette partie du programme, car je suis en train d'optimiser l'ensemble du code. Je pense que la latence associée à l'écriture du résultat du calcul à chaque cycle ralentit considérablement les performances du logiciel. P>
Je suis confus parce que je n'ai aucune expérience dans la programmation parallèle et les fichiers de faible niveau d'E / S. J'ai pensé à certaines techniques abstraites que j'ai imaginées que je pouvais implémenter, car je suis programmée pour des machines modernes (éventuellement multi-noyau) avec UNIX OSES: P>
Cependant, je ne sais pas comment mieux les mettre en œuvre et les combiner de manière appropriée. P> méthode code> 'S code> écrire () code> pour écrire les données au format binaire à chaque itération. p>
mmap code> (la taille du fichier pourrait être énorme, de l'ordre de GBS, est-ce suffisamment robuste?) Li>
ul>
4 Réponses :
Il est préférable de scinder l'opération en deux processus indépendants: Essentiellement, si les données sont produites beaucoup plus rapidement qu'elles ne peuvent éventuellement être stockées, vous finirez rapidement de tenir la majeure partie de celle-ci dans le tampon. Dans ce cas, votre approche réelle semble être assez raisonnable que cela puisse être faite par programme alors d'améliorer la situation. P> producteur de données code> et
écriture de fichier code>.
PRODUCTION DE DONNÉES CODE> Utiliserait un certain tampon pour le passage des données sages d'itération et
L'écriture de fichiers code> utiliserait une file d'attente pour stocker des demandes d'écriture. Ensuite,
producteur de données code> posterait simplement une demande d'écriture et continuerait, tandis que
écrit de fichier code> va faire face à l'écriture en arrière-plan. P>
Pourquoi pensez-vous que vous pouvez faire un meilleur travail de mémoire tampon que le cache du bloc d'exploitation déjà?
@Stevec parce qu'il est généralement préférable de mettre en œuvre l'algorithme de manière déterministe que de compter sur les caractéristiques dépendantes de la mise en œuvre. Je veux dire, bloquer le cache est i> bien, mais cela pourrait ou ne pas correspondre à la situation spécifique. Cela pourrait ne pas être aussi portable, ce n'est peut-être pas aussi rapide, etc., et l'OP n'était pas trop spécifique de toute façon :)
Dans ce cas, vous ne devriez pas passer à travers deux couches de tampon, mais simplement contourner le système de fichiers et écrire sur le disque brut. C'est "plus déterministe" et vous pouvez "faire correspondre la situation spécifique". Personnellement, je doute que vous puissiez faire un meilleur travail que les auteurs du système de fichiers.
@Stevec: Je n'essaierais même pas de, mais vous avez manqué le point. Ce qui est: les langues de programme polyvalentes sont agnostiques à tout support OS (et C ++ est). Le tampon du système d'exploitation peut être éteint ou complètement absent pour de nombreuses raisons, et nous ne pouvons pas compter sur elle à moins que sa présence soit explicitement requise ou garantie.
"Utilisation de MMAP (la taille du fichier pourrait être énorme, de l'ordre de GBS, est-ce approche assez robuste?) " p> blockQuote>
MMAP est la méthode de chargement des programmes d'exploitation, des bibliothèques partagées et du fichier de page / swap - elle est aussi robuste que tout autre fichier d'E / S et de performances généralement plus élevées. P>
Mais sur la plupart des systèmes d'exploitation, il est mauvais / difficile / impossible d'étendre la taille d'un fichier mappé lorsqu'il est utilisé. Donc, si vous connaissez la taille des données ou que vous ne lisez que, c'est génial. Pour un journal / décharge que vous ajoutez continuellement, il est moins sutable - sauf si vous connaissez une taille maximale. P>
Je connais la taille des données, mais il n'y aura aucun problème avec des systèmes 32 bits si j'ai un fichier de certains gigaoctets?
@Fiat - c'est le gros avantage du MMAP. Vous pouvez mapper plusieurs vues dans le fichier avec des décalages afin que vous puissiez utiliser une fenêtre pour accéder à une partie d'un fichier aussi grand que votre FS permettra. Les détails dépendent de votre système d'exploitation
Bien sûr, l'écriture dans un fichier à chaque itération est inefficace et la plus susceptible de ralentir votre calcul. (En règle générale, dépend de votre cas d'actuel) p>
Vous devez utiliser un producteur em> -> consommateur < / em> modèle de conception. Ils seront liés par une file d'attente, comme une bande transporteuse. P>
En divisant les deux, vous pouvez augmenter plus facilement les performances car chaque processus est plus simple et a moins d'interférences de l'autre. P>
Il y a Pratiquement, vous utilisez des threads et une file d'attente synchronisée entre eux. Pour les astuces de mise en œuvre, consultez ici , notamment §18.12 "Le modèle de producteur-consommateur ". P>
À propos de la gestion des flux, vous devez ajouter un peu plus de complexité en sélectionnant une "taille de la file d'attente maximale" et en faisant attendre le (s) producteur (s) si la file d'attente n'a pas assez d'espace. Méfiez-vous des blocages alors, le code soigneusement. (Voir le lien Wikipedia que j'ai donné à ce sujet) P>
Remarque: c'est une bonne idée d'utiliser des fils de boost car les threads ne sont pas très portables. (Eh bien, ils sont depuis C ++ 0X mais la disponibilité C ++ 0x n'est pas encore bonne) p>
Mais, compte tenu de la taille des données, comment gérer le cas où le producteur est si rapide qu'il produit quelque chose qui ne peut pas être stocké en mémoire avant que le consommateur ne parvienne à le sauvegarder sur le disque?
@Fiat Lux Eh bien, si vous produisez des données plus rapides que vous ne pouvez être stockés sur votre système de fichiers, vous avez un problème assez élémentaire totalement indépendant de toutes les astuces logicielles que vous faites. Si votre bande passante est trop petite, tôt ou tard, vous manquerez d'espace tampon, puis vous devrez gérer cette affaire de toute façon.
@FiaLux C'est pourquoi j'ai dit "Procducer ... seulement ralentir si le consommateur ne peut pas s'en occuper". J'ai édité d'ajouter un lien à un exemple de mise en œuvre + amélioration suggérée. Vous devrez faire attendre les producteurs si la mémoire est pleine.
Si vous ne voulez pas jouer avec faire des trucs dans un fil différent, vous pouvez essayer d'utiliser AIO_WRITE () , qui permet des écritures asynchrones. Essentiellement, vous donnez à l'os le tampon à écrire, et la fonction renvoie immédiatement et termine l'écriture lorsque votre programme se poursuit, vous pouvez vérifier plus tard pour voir si l'écriture est terminée. P>
Cette solution souffre toujours du Producteur / Problème de consommation mentionné dans d'autres réponses, si votre algorithme produit des données plus rapidement qu'il ne peut être écrit, vous risqueriez d'être hors de mémoire pour stocker les résultats entre l'algorithme et l'écriture, Donc, vous devriez l'essayer et voir comment cela fonctionne. P>
"Je pense que la latence associée à l'écriture du résultat du calcul à chaque cycle ralentit considérablement les performances du logiciel." Le sentez-vous ou vous avez profilé votre code?
Avez-vous profilé le code pour vous assurer que vos sentiments sur la latence sont corrects?
@LightnessRacesinorbit Quelles sont les techniques les plus rapides pour écrire les données et faire le calcul en même temps et comment les mettre en œuvre. Je sais que c'est une question très fondamentale, mais je ne suis pas un expert en mettant en œuvre des optimisations encore simples, telles qu'un tampon. Donc, j'aimerais savoir quelles apis et techniques je devrais étudier
Si vous voulez des suggestions intelligentes, vous devez donner quelques chiffres.
Les problèmes de N-corporels exigent, en général, O (N ^ 2) Opérations pour chaque itération. Écrire vos données nécessite des opérations O (n). En supposant que votre programme soit conforme à ces généralités, vous trouverez l'optimisation de chaque itération produira de meilleurs résultats que d'essayer d'optimiser la sortie. Bien sûr, vous ne devriez pas prendre ma parole sur ceci avant que vous ayez, comme l'a suggéré Alessandro, a complètement profilé votre programme de voir où existent les goulots d'étranglement.
@ AlessandroTeruzzi, grizzly, je n'ai pas profilé le code, mais je peux intercaler des calculs sans écrire leur résultat sur le disque. Lorsque je les ajoute, le logiciel ne ralentit pas considérablement. À mon avis, cela signifie que les E / S du disque sont lents par rapport au calcul
@andand (wow .. Je suis impressionné par la quantité et la qualité des réponses). Ce que j'essaie maintenant de faire est de maximiser le nombre d'itérations, pas le nombre de corps, le «coefficient de la N» dans la partie O (n) est élevé. Quoi qu'il en soit, grâce à tout pour souligner la nécessité de profiler le code (je tiens à faire comment faire, je suis débutant ..) Et merci à vous pour votre observation
Ce n'est pas une question très spécifique.
@andand: "O (n ^ 2) ... Tu trouveras l'optimisation de chaque itération produira de meilleurs résultats que d'essayer d'optimiser la sortie". Vous supposez qu'il n'utilise pas la sommation ewald ou la méthode Multiole rapide, que le précieux constant pour le disque IO est insignifiant et que N i> est grand. Je doute que ces hypothèses soient vraies. La question indique que le nombre d'itérations est important et non le nombre d'organes. Le disque IO est des ordres de magnitude plus lentement que l'arithmétique sur la CPU.