Grand tableau, manque de RAM, écriture/lecture sur HD

guelowrd Messages postés 5 Date d'inscription lundi 29 octobre 2007 Statut Membre Dernière intervention 20 mai 2009 - 21 nov. 2008 à 19:55
guelowrd Messages postés 5 Date d'inscription lundi 29 octobre 2007 Statut Membre Dernière intervention 20 mai 2009 - 3 déc. 2008 à 14:20
Bonjour à tous,
Voici mon problème : je veux remplir un grand tableau de doubles (1,000,000 lignes x qq centaines de colonnes) dans une sub, puis le réutiliser dans une autre sub colonne par colonne.
J'ai évidemment un problème de mémoire, donc j'écris le tableau dans un fichier csv que je relis dans la seconde sub.
Mon problème : c'est très très lent. Voici le concept du code dans sa version actuelle (lente...), je suis ouvert à toute idée.

public sub ecriture()
dim i, j as long
dim ligne as string
dim ecrire as StreamWriter = new StreamWriter("C:\temp\fichier_temporaire.csv")
for i = 0 to nb_lignes - 1
   ligne = nothing
   for j = 0 to nb_colonnes - 1
      ...
      ligne &= un_réel_double_que_j'ai_calculé_avant & ";"
   next j
   ecrire.WriteLine(ligne)
next i
ecrire.close()
end sub

public sub lecture()
dim i, j, j_temp as integer
dim ligne as string
dim colonne() as double
redim colonne(nb_colonnes - 1)
dim lire as Streamreader = New StreamReader("C:\temp\fichier_temporaire.csv")
while i_temp < nb_colonnes
   for j = j_temp to nb_colonnes - 1
      lire.BaseStream.Seek(0, SeekOrigin.Begin)
      for i = 0 to nb_lignes - 1
         ligne = lire.ReadLine
         colonne(i) += CDbl(ligne.Split(";")(j)
      next i
      if une_condition_calculée avec les colonne(j) Or j = nb_colonnes - 1 then
         j_temp = j + 1
         exit for
      end if
   next i
end while
lire.close()
end sub

J'espère que j'ai été clair et que ce problème vous inspirera.

7 réponses

jesusonline Messages postés 6814 Date d'inscription dimanche 15 décembre 2002 Statut Membre Dernière intervention 13 octobre 2010 29
21 nov. 2008 à 20:41
Bonsoir,

Il est possible d'optimiser ton code de plusieurs facons :

sans "modifier" ton code tu peux déjà supprimer tous ce qui est concatènation de string inutile. Plutot que de déclarer une variable ligne, écrit directement avec ecrire.Write dans ton stream
plutot que de calculer à chaque fois nbligne - 1 et nbcol-1 stock le dans une variable que tu fais une fois.

dans lecture, tu fais un split(";") sur chaque ligne et chaque colonne, tu peux plutot te débrouiller pour le faire qu'une fois par ligne ? itérer sur les lignes plutot que sur les colonnes ?

Sinon, tu as vraiment besoin d'écrire dans un fichier ? si c'est pas le cas, tu peux retravailler ton algo pour que ecrire et lire soit combiné.

Bref, si tu veux vraiment qu'on t'aide à optimiser le code, il va nous falloir un peu plus de détail sur tes calculs métiers

<hr />Cyril - MVP ASP.net - MCPD ASP.net & MCTS SQL - Consultant indépendant
0
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
23 nov. 2008 à 11:59
La 1ere chose à faire est d'effacer le tout.

Pourquoi du format CSV ??? pas trouvé de raison, donc aucun format.
Si tu veux des perfs, faut éviter les manips de transformation binaire <=> ascii.
Ecrit et relis direct en binaire.

ciao...
BruNews, MVP VC++
0
guelowrd Messages postés 5 Date d'inscription lundi 29 octobre 2007 Statut Membre Dernière intervention 20 mai 2009
24 nov. 2008 à 11:34
>BruNews : mais comment je fais pour recuperer les données qui m'intéressent dans la seconde partie du code ? en gros, il faut que j recupere la colonne j, et en binaire ca me semble un peu galère...

>jesusonline : je suis pas sûr que ma variable ligne bouffe énormément d'espace ou de perf, mais je prends bien note de ton conseil. Ensuite, je suis obligé d'itérer sur les colonnes puis sur les lignes pour la lecture à cause du While j_temp < nb_colonnes - 1 et des calculs qui suivent... en gros je récupère la colonne j du grand tableau imprimé dans le fichier csv, je fais des calculs avec tous les nombres qu'il y a dedans, ensuite je fais un test sur le résultats de ce calcul (if une_condition_calculée avec les colonne(j) then ... exit for) et si la condition est pas vérifiée, je recommence en ajoutant la colonne j+1, refait le calcul, revérifie la condition, etc. Et je suis obligé d'écrire dans un fichier étant donné la taille du tableau en question.
0
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
24 nov. 2008 à 14:46
Si on plaque des Double  (par exemple) c'est 8 octets chacun, je veux le 3eme je lis à 16 octets partant du début, etc...
Il est clair que la taille de code est généralement inversement proportionnelle aux perfs attendues, des Split() et autres plaisanteries c'est plus court à écrire mais infiniment plus long en traitement.

ciao...
BruNews, MVP VC++
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
guelowrd Messages postés 5 Date d'inscription lundi 29 octobre 2007 Statut Membre Dernière intervention 20 mai 2009
24 nov. 2008 à 14:56
ok jessaye ca aujourd'hui si jai le temps ou demain et je vous fais un feedback asap
0
jesusonline Messages postés 6814 Date d'inscription dimanche 15 décembre 2002 Statut Membre Dernière intervention 13 octobre 2010 29
24 nov. 2008 à 17:52
c'est pas parceque c'est un grand tableau que tu dois nécessairement l'enregistrer sur le disque ... je pense que tu dois revoir ton algorithme sur papier afin de l'optimiser avant de l'écrire dans un quelconque langage.

D'après ce que je vois tu as 2 parties à ton algo :
 - un prétraitement où tu construit ton grand tableau
 - un traitement sur les colonnes

Dans ton prétraitement, tu ne peux pas construire ton grand tableau colonne par colonne ? t'es obligé de faire toute la ligne d'un coup ? tu peux pas revenir sur ta ligne plus tard ?

C'est possible d'avoir du code reproductible ? si j'ai le temps, j'aimerais voir jusqu'où j'arrive à optimiser du code .net avant de devoir passer par du natif (beurk, n'est-ce pas Brunews ;))

<hr />Cyril - MVP ASP.net - MCPD ASP.net & MCTS SQL - Consultant indépendant
0
guelowrd Messages postés 5 Date d'inscription lundi 29 octobre 2007 Statut Membre Dernière intervention 20 mai 2009
3 déc. 2008 à 14:20
reformulation du problème : en gros, voici un bout de code qui marche mais dont l'exécution est trop longue à mon goût (l'étape de lecture prend 5sec dans ce cas avec 10,000 lignes et 100 colonnes, sachant que j'aurais besoin de 1,000,000 de lignes...). La structure inversée de la boucle dans la sub "read()" empêche à mon sens le multithreading (MAIS je précise que j'ai besoin de la garder comme ça) ; 1. êtes-vous d'accord ? 2. d'autres idées (multithreader me semble être le seul moyen pour optimiser mais bon, je suis pas informaticien...).
Merci.

Imports

System.IO
Imports System.Management

Imports
System.Math

Public
Class RW_csv

#Region "Public Variables Declaration"

            Public temp_path, temp_name AsString

            Public writer As StreamWriter

            Public bin_writer As BinaryWriter

            Public reader As StreamReader

            Public bin_reader As BinaryReader

#EndRegion
PublicSub main()

            temp_path = "D:\TEMP"

            temp_name = "temp"

            Try

                     Call write()

                     Call read()

                     File.Delete(temp_path & temp_name & ".dat")

            Catch ex As Exception

                     MsgBox("Error happened..." & Chr(10) & ex.ToString, MsgBoxStyle.MsgBoxSetForeground, "Error!")

            EndTry

EndSub

PublicSub write()

            Dim start AsDouble = DateTime.Now.Ticks

            temp_stream = New FileStream(temp_path & temp_name & ".dat", FileMode.Create)

            bin_writer = New BinaryWriter(temp_stream)

            Dim i, j AsInteger

            For i = 0 To 9999

                     For j = 0 To 99

                              bin_writer.Write(CDbl(i * 100 + j))

                     Next j

            Next i

            bin_writer.Close()

            Dim finish AsDouble = DateTime.Now.Ticks

            Console.WriteLine((finish - start) \ 10000 & "ms")

EndSub

PublicSub read()

            Dim start AsDouble = DateTime.Now.Ticks

            temp_stream = New FileStream(temp_path & temp_name & ".dat", FileMode.Open)

            bin_reader = New BinaryReader(temp_stream)

            Dim i, j AsInteger

            Dim output(99)() AsDouble

            For j = 0 To 99

                     ReDim output(j)(99)

                     bin_reader.BaseStream.Seek(j * 8, SeekOrigin.Begin)

                     For i = 0 To 9999

                              output(j)(i) = bin_reader.ReadDouble()

                              bin_reader.BaseStream.Seek(99 * 8, SeekOrigin.Current)

                     Next i

            Next j

bin_reader.Close()

Dim finish AsDouble = DateTime.Now.Ticks

Console.WriteLine((finish - start) \ 10000 & "ms")

EndSub
End
Class
0
Rejoignez-nous