6
votes

Traiter le même fichier dans deux threads en utilisant ifstream

J'ai un fichier d'entrée dans mon application contenant une vaste quantité d'informations. Lecture sur elle séquentiellement, et uniquement un seul décalage de fichier à la fois ne suffit pas pour l'utilisation de mon application. Idéalement, je voudrais avoir deux threads, qui ont une lecture distincte ifstream S à partir de deux compensations de fichiers uniques du même fichier. Je ne peux pas simplement commencer un ifstream up, puis en effectuer une copie à l'aide de son constructeur de copie (depuis son incord). alors, comment puis-je gérer cela?

Immédiatement, je peux penser à deux manières,

  1. construire un nouveau ifstream pour le deuxième thread, ouvrez-le sur le même fichier.
  2. Partagez une seule instance d'un ifstream sur les deux threads (en utilisant par exemple boost :: Shared_ptr <> ). Recherchez le décalage du fichier approprié que le thread actuel est actuellement intéressé, lorsque le thread obtient une tranche de temps.

    est l'une de ces deux méthodes préférées?

    y a-t-il une troisième (ou quatrième) option que je n'ai pas encore pensé à?

    Évidemment, je suis finalement limité par le disque dur qui devait tourner en arrière, mais ce que je suis intéressé à tirer parti de (si possible), est une mise en cache de disque de niveau d'exploitation dans les deux décalages de fichiers simultanément.

    Merci.


0 commentaires

5 Réponses :


6
votes

entre les deux, je préférerais la seconde. Avoir deux ouvertures du même fichier peut provoquer une vue incohérente entre les fichiers, en fonction du système d'exploitation sous-jacent.

Pour une troisième option, transmettez une référence ou un pointeur brut dans l'autre thread. Tant que la sémantique est qu'un thread "possède" l'Istream, le pointeur brut ou la référence conviennent bien.

Notez enfin que sur la grande majorité du matériel, le disque est le goulot d'étranglement, pas la CPU, lors du chargement de fichiers volumineux. L'utilisation de deux threads rendra cela pire car vous tournez un accès séquentiel d'accès à un accès aléatoire. Les disques durs typiques peuvent faire peut-être 100 Mo / s séquentiellement, mais de haut sur 3 ou 4 Mo / s d'accès aléatoire.


2 commentaires

Notez qu'il demande à propos de lisant un fichier avec std :: ifstream . Il n'aura pas à s'inquiéter de vues incohérentes dans ce cas.


@Cory: C'est vrai dans ce cas particulier. Je pense plus généralement.



12
votes

Deux std :: ifstream Les instances seront probablement la meilleure option ici. Les disques durs modernes sont optimisés pour une grande file d'attente de demandes d'E / S.La lecture à partir de deux std :: ifstream Les instances doivent concurremment donner des performances assez agréables.

Si vous avez un seul std :: ifstream Vous devrez vous inquiéter de la synchronisation de l'accès à celui-ci, plus il pourrait vaincre la mise en cache d'accès à l'accès séquentielle du système d'exploitation, entraînant des performances plus pauvres. .


2 commentaires

Ceci est vrai que si l'accès initial était aléatoire. Si l'accès initial était séquentiel, l'accès aléatoire induit par les deux threads ferait pire les choses.


En effet. Il déclare explicitement que la lutte de manière séquentielle n'est pas suffisante. Dans ce cas où il doit effectuer un accès aléatoire, deux demandes simultanées vont être meilleures.



4
votes

Autre option:

  • Mémoire - Carte du fichier, créez autant d'objets de mémoire Istream que vous le souhaitez. ( Istrstream est bon pour cela, istringstream n'est pas).

5 commentaires

Votre compilateur doit-il prendre en charge une standard C ++ sur C ++ pour l'utiliser?


@J T: La cartographie de la mémoire n'est pas couverte par la norme. Vous devrez utiliser les appels qu'il faudrait sur votre plate-forme. Sur POSIX, ce sera mmap , sous Windows qui sera CreateFilemapping + MapViewOffile


La cartographie de la mémoire ne fait pas partie de la norme. Boost Interprocess a un support de cartographie de mémoire multiplate-forme, cependant.


Je pensais std :: strtstream a été obsolète ?


@awoodland: c'est. Et il est aussi obsolète en C ++ 0x. Étant donné que les dépréciations impliquent, "obligatoirement d'être présent dans toute mise en œuvre conforme", nous sommes bons à partir ;-) Une alternative consiste à réécrire le code pour fonctionner directement sur la matrice mappée, plutôt que via un flux, mais en utilisant Istrstream , qui est nécessairement en lecture seule, est assez inoffensif.



0
votes

Mon vote serait un seul lecteur, qui maintient les données à plusieurs threads de travailleurs.

Si votre fichier est sur un seul disque, plusieurs lecteurs tueront vos performances de lecture. Oui, votre noyau peut avoir des capacités de mise en cache ou de mise en file d'attente fantastiques, mais il va dépenser plus de temps à la recherche de temps que de lire des données.


5 commentaires

Il y aura tout autant de recherche sur le disque lorsqu'il recherche dans le fichier. Et la recherche constante de la recherche de stratégies de lecture à l'avance que le système d'exploitation pourrait utiliser.


@ James-Kanze Lecture d'un fichier séquentiellement à partir de 2 processus ou threads différents aura beaucoup plus de disque de disque que d'un processus ou d'un seul processus qui cherche autour du fichier. Analogie: Pensez à 2 personnes à lire du même livre.


Ok, mais dans votre analogie du livre, si une personne célibataire voulait lire simultanément les chapitres 4 et 8, ne devra-t-il pas renvoyer les pages autant de choses autant?


@JT: Oui, mais Lisez Post de OP: .. LIRE. chapitre à la fois. Il peut décider quand retourner à l'autre chapitre.


"Lire le dessus de cela séquentiellement ... n'est pas suffisant"



1
votes

Cela dépend vraiment de votre système. Un système moderne va généralement lire en avant; La recherche dans le dossier est susceptible d'inhiber cela, alors devrait définitivement être évité.

Il peut être utile d'expérimenter la lecture de votre système: Ouvrez le fichier, puis lisez la première moitié de cela séquentiellement et voyez comment long qui prend. Puis ouvrez-le, cherchez au milieu et lisez la seconde mi-séquentiellement. (Sur certains systèmes que j'ai vus dans le passé, un simple chercher, à tout moment, fera désactiver la lecture.) Enfin, ouvrez-le, puis lire tous les autres enregistrements; Cela simulera deux threads en utilisant le même Descripteur de fichier. (Pour tous ces tests, utilisez des enregistrements de longueur fixe et Ouvrir en mode binaire. Prenez également les mesures nécessaires pour assurer que toutes les données du fichier sont purgées à partir du cache du système d'exploitation avant Démarrer le test-sous Unix, copiant un fichier de 10 ou 20 gigaoctets à / dev / null est généralement suffisant pour cela.

Cela vous donnera quelques idées, mais pour être vraiment certain, le meilleur la solution serait de tester les cas réels. Je serais surpris si partager un simple ifstream (et donc un seul descripteur de fichier), et constamment Cherche, gagné, mais vous ne savez jamais.

Je recommanderais également des solutions spécifiques au système tels que MMAP , mais si vous avez obtenu autant de données, il y a de bonnes chances que vous ne puissiez pas la cartographier Tout en un va quand même. (Vous pouvez toujours utiliser mmap , des sections de cartographie de celui-ci à la fois, mais cela devient beaucoup plus compliqué.)

Enfin, serait-il possible d'obtenir les données déjà coupées en fichiers plus petits? Cela pourrait être la solution la plus rapide de tous. (Idéalement, cela serait fait lorsque les données sont générées ou importées dans la système.)


1 commentaires

C'était un mélange pour votre solution et celle que j'ai sélectionnée. +1