Paralléliser boucle while avec OpenMP
J'ai un très grand fichier de données, et chaque enregistrement dans ce fichier de données a 4 lignes. J'ai écrit un très simple C programme pour analyser des fichiers de ce type et d'imprimer des informations utiles. L'idée de base du programme de cette.
int main()
{
char buffer[BUFFER_SIZE];
while(fgets(buffer, BUFFER_SIZE, stdin))
{
fgets(buffer, BUFFER_SIZE, stdin);
do_some_simple_processing_on_the_second_line_of_the_record(buffer);
fgets(buffer, BUFFER_SIZE, stdin);
fgets(buffer, BUFFER_SIZE, stdin);
}
print_out_result();
}
Bien sûr, cela laisse de côté certains détails (la santé mentale/vérification des erreurs, etc), mais ce n'est pas pertinente à la question.
Le programme fonctionne très bien, mais les fichiers de données avec lesquelles je travaille sont énormes. J'ai pensé que je voudrais essayer d'accélérer le programme par la parallélisation de la boucle avec OpenMP. Après un peu de recherche, cependant, il semble que OpenMP ne peut gérer que for
boucles d'où le nombre d'itérations est de savoir à l'avance. Car je ne sais pas la taille des fichiers à l'avance, et même de simples commandes comme wc -l
prendre du temps pour s'exécuter, comment puis-je paralléliser ce programme?
OriginalL'auteur Daniel Standage | 2011-09-23
Vous devez vous connecter pour publier un commentaire.
Avez-vous vérifié que votre processus est en fait lié au PROCESSEUR et pas d'e/S? Votre code ressemble beaucoup à e/S code, qui ne gagneraient rien à la parallélisation.
Oui. Exécutez le programme et regardez la sortie de sommet (sous Windows, le Gestionnaire des Tâches) en étroite collaboration. Si l'utilisation du PROCESSEUR n'est pas aller jusqu'à 100% (ou 1/#PROCESSEUR pour plusieurs Processeurs), le processus est le plus susceptible de ne pas CPU limited. Il sera en attente pour le disque, la plupart du temps.
Oh, et avec la commande top, vous pouvez également regarder le pourcentage de temps CPU qui est passé en attente - I/O-lié processus font que le temps de montée à #attente-threads/#CPU, par exemple, 25% pour les 4 Processeurs et un fil dans votre programme en attente d'entrée.
Eh, bien sûr, mais en vous il n'y a pas de #buymeanSSD directive OpenMP ou pthreads.
que serait
#pragma omp scale take(money) yield(SSD)
?OriginalL'auteur thiton
Comme thiton mentionné, ce code peut être I/O délimitée. Cependant, ces jours-ci de nombreux ordinateurs peuvent avoir des disques Ssd et à haut débit des disques RAID. Dans de tels cas, vous pouvez obtenir de l'accélération de la parallélisation. En outre, si le calcul n'est pas anodin, alors paralléliser les victoires. Même si le I/O est effectivement sérialisé en raison jusqu'à la saturation de la bande passante, vous pouvez toujours obtenir de l'accélération en distribuant le calcul de multicœur.
Revenir à la question elle-même, vous pouvez parallélisation de cette boucle par OpenMP. Avec
stdin
, je n'ai aucune idée de paralléliser parce qu'il doit lire dans l'ordre, et sans information préalable de la fin. Toutefois, si vous travaillez habituellement, un fichier, vous pouvez le faire.Voici mon code avec
omp parallel
. J'ai utilisé une API Win32 et MSVC CRT:Ce code ressemble un peu sale parce que j'avais besoin précisément de répartir le montant du fichier à lire. Toutefois, le code est assez simple. Une chose à garder à l'esprit est que vous devez avoir par thread pointeur de fichier. Vous ne pouvez pas tout simplement partager un pointeur de fichier en raison de la structure de données interne ne peut pas être thread-safe. En outre, ce code peut être parallélisée par
parallel for
. Mais, je pense que cette approche est plus naturel.Simple des résultats expérimentaux
J'ai testé ce code pour lire un fichier de 10 go sur un disque dur (WD Green 2 to) et un SSD (Intel 120 GO).
Avec un disque dur, oui, pas d'accélérations ont été obtenus. Même ralentissement a été observé. Cela montre clairement que ce code est I/O délimitée. Ce code a pratiquement aucun calcul. Just I/O.
Cependant, avec un SSD, j'ai eu une accélération de 1,2 avec 4 cœurs. Oui, l'accélération est faible. Mais, vous pouvez toujours obtenir avec SSD. Et, si le calcul devient un peu plus (je viens de mettre sur un très court occupé-boucle d'attente), la vitesse serait importante. J'ai été en mesure d'obtenir gain de 2,5.
En somme, je voudrais vous recommandons d'essayer de paralléliser ce code.
Aussi, si le calcul n'est pas anodin, je vous recommande pipelining. Le code ci-dessus simplement se divise en plusieurs gros morceaux, provoquant une faible efficacité de la mémoire cache. Cependant, d'un pipeline de parallélisation peut donner une meilleure utilisation du cache. Essayez d'utiliser TBB pour le pipeline de parallélisation. Ils fournissent un moyen simple de pipeline de construire.
Daniel, merci de regarder le code, et vous verrez la plupart de même avec Unix. Il suffit de remplacer certains fichiers volumineux fonctions de gestion comme
lseek
etgettimeofday
.OriginalL'auteur minjang
En réponse à "la garde", je ne pense pas que votre code d'optimiser quoi que ce soit ici. Il y a beaucoup de bon malentendu à propos de cette déclaration "#pragma omp parallel", celui-ci serait en fait juste lancer le fils, sans le "de" mot-clé, tous les threads va juste permettre d'exécuter tout les codes suivants. Si votre code devrait être dupliquer le calcul sur chaque fil. En réponse à Daniel, vous avez eu raison, OpenMP ne peut pas optimiser la boucle while, la seule façon d'optimiser, c'est par la restructuration du code, de sorte que l'itération est connu à l'avance (comme lors de la boucle une fois avec un compteur). Désolé de poster une autre réponse, car je ne peux pas commenter pour l'instant, mais j'espère que cela efface la commune de malentendus.
OriginalL'auteur Guang Mo