2011-05-19 1 views
3

J'ai un programme C++ qui transpose une très grande matrice. La matrice est trop volumineuse pour être conservée en mémoire, donc j'écrivais chaque colonne dans un fichier temporaire séparé, puis concaténais les fichiers temporaires une fois que toute la matrice avait été traitée. Cependant, je constate maintenant que je me heurte au problème d'avoir trop de fichiers temporaires ouverts (c'est-à-dire que le système d'exploitation ne me permet pas d'ouvrir suffisamment de fichiers temporaires). Existe-t-il une méthode portable système pour vérifier (et, espérons-le, changer) le nombre maximum de fichiers ouverts autorisés? Je réalise que je pourrais fermer chaque fichier temporaire et ne le rouvrir que lorsque cela est nécessaire, mais je suis inquiet de l'impact sur les performances.Système C/C++ façon portable pour modifier le nombre maximum de fichiers ouverts

Mon code fonctionne comme suit (pseudo-code - pas garanti):

int Ncol=5000; // For example - could be much bigger. 
int Nrow=50000; // For example - in reality much bigger. 

// Stage 1 - create temp files 
vector<ofstream *> tmp_files(Ncol); // Vector of temp file pointers. 
vector<string> tmp_filenames(Ncol); // Vector of temp file names. 
for (unsigned int ui=0; ui<Ncol; ui++) 
{ 
    string filename(tmpnam(NULL)); // Get temp filename. 
    ofstream *tmp_file = new ofstream(filename.c_str()); 
    if (!tmp_file->good()) 
     error("Could not open temp file.\n"); // Call error function 
    (*tmp_file) << "Column" << ui; 
    tmp_files[ui] = tmp_file; 
    tmp_filenames[ui] = filename; 
} 

// Stage 2 - read input file and write each column to temp file 
ifstream input_file(input_filename.c_str()); 
for (unsigned int s=0; s<Nrow; s++) 
{ 
     int input_num; 
     ofstream *tmp_file; 
     for (unsigned int ui=0; ui<Ncol; ui++) 
     { 
      input_file >> input_num; 
      tmp_file = tmp_files[ui];   // Get temp file pointer 
      (*tmp_file) << "\t" << input_num; // Write entry to temp file. 
     } 
} 
input_file.close(); 

// Stage 3 - concatenate temp files into output file and clean up. 
ofstream output_file("out.txt"); 
for (unsigned int ui=0; ui<Ncol; ui++) 
{ 
     string tmp_line; 
     // Close temp file 
     ofstream *tmp_file = tmp_files[ui]; 
     (*tmp_file) << endl; 
     tmp_file->close(); 

     // Read from temp file and write to output file. 
     ifstream read_file(tmp_filenames[ui].c_str()); 
     if (!read_file.good()) 
      error("Could not open tmp file for reading."); // Call error function 
     getline(read_file, tmp_line); 
     output_file << tmp_line << endl; 
     read_file.close(); 

     // Delete temp file. 
     remove(tmp_filenames[ui].c_str()); 
} 
output_file.close(); 

Un grand merci à l'avance!

Adam

+0

portables du système dans un sens des fenêtres <-> * nix portables? Ne pensez pas que vous pouvez définir ce paramètre sur Windows. – RedX

+0

Si vous stockez ces chiffres sous forme de texte, vous allez vraiment punir votre performance avec toutes les conversions de texte en valeurs numériques. – Andrew

+0

Le format que je suis en train de lire est un format bioinformatique standardisé dans lequel les colonnes peuvent effectivement contenir divers nombres, chaînes de texte, etc. La conversion du texte en numérique est malheureusement inévitable. (Le format en question est ici: http://www.1000genomes.org/wiki/Analysis/Variant%20Call%20Format/vcf-variant-call-format-version-41) – Adam

Répondre

2

Il y a au moins deux limites:

  • le système d'exploitation peut imposer une limite; sous Unix (sh, bash, et de coquillages similaires), utilisez ulimit pour modifier la limite, dans les limites autorisées par le sysadmin
  • la mise en œuvre de la bibliothèque C peut avoir une limite aussi bien; vous aurez probablement besoin de recompiler la bibliothèque pour changer cela

Une meilleure solution est d'éviter d'avoir autant de fichiers ouverts. Dans un de mes propres programmes, j'ai écrit un wrapper autour de l'abstraction du fichier (c'était en Python, mais le principe est le même en C), qui garde la position actuelle du fichier dans chaque fichier et ouvre/ferme les fichiers si nécessaire , en conservant un pool de fichiers actuellement ouverts.

1

Il n'y a pas un moyen portable pour changer le nombre maximum de fichiers ouverts. Les limites de ce type ont tendance à être imposées par le système d'exploitation et sont donc spécifiques à l'OS.

Votre meilleur pari est de réduire le nombre de fichiers que vous avez ouverts à un moment donné.

0

Que diriez-vous juste de faire un gros fichier au lieu de nombreux petits fichiers temporaires? Seek est une opération bon marché. Et vos colonnes devraient toutes être de la même taille de toute façon. Vous devriez être en mesure de positionner votre pointeur de fichier là où vous en avez besoin pour accéder à la colonne.

// something like... 

column_position = sizeof(double)*Nrows*column ; 
is.seekg(column_position) ; 
double column[Nrows] ; 
for(i = 0 ; i < Nrows ; i++) 
    is >> column[i] ; 
+0

Pourriez-vous développer ce que vous voulez dire? Chercher dans le fichier original pour trouver la colonne? Ou chercher dans le fichier temporaire? Désolé - je ne suis pas. – Adam

+0

Malheureusement, le fichier que je suis en train de lire est du texte (un format bioinformatique standardisé) et donc il n'est pas possible de chercher de cette manière. Merci pour la suggestion cependant. – Adam

+0

Et vos fichiers temporaires? Dans quel format sont-ils? – Andrew

1

Vous pouvez normaliser le fichier d'entrée dans un fichier temporaire, de sorte que chaque entrée occupe le même nombre de caractères. Vous pourriez même envisager d'enregistrer ce fichier temporaire en tant que binaire (en utilisant 4/8 octets par nombre au lieu de 1 octet par chiffre décimal). De cette façon, vous pouvez calculer la position de chaque entrée dans le fichier à partir de ses coordonnées dans la matrice. Ensuite, vous pouvez accéder à des entrées spécifiques en faisant un std::istream::seekg et vous n'avez pas à vous soucier d'une limite sur le nombre de fichiers ouverts.

0

"La matrice est trop grande pour être conservée en mémoire". Cependant, il est très probable que la matrice s'insère dans votre espace d'adressage. (Si la matrice ne rentre pas dans 2^64 octets, vous aurez besoin d'un système de fichiers très impressionnant pour contenir tous ces fichiers temporaires.) Donc, ne vous inquiétez pas pour les fichiers temporaires. Laissez le système d'exploitation gérer le fonctionnement du swap sur le disque. Vous avez juste besoin de vous assurer que vous accédez à la mémoire d'une manière qui permette l'échange. En pratique, cela signifie que vous devez avoir une localité de référence. Mais avec 16 Go de RAM, vous pouvez avoir environ 4 millions de pages RAM.Si votre nombre de colonnes est significativement plus petit, il ne devrait pas y avoir de problème.

(Ne pas utiliser les systèmes 32 bits pour cela, c'est tout simplement pas vaut la peine)

Questions connexes