Optimisation du traitement des chaînes - VB/VBA/VBS - Programmation
Marsh Posté le 24-08-2003 à 00:25:40
optimisation et vb c'est pas contradictoire ça?
calcule le temps nécessaire avec le mid et la méthode du tableau... tu seras c'est lequel des deux qui est le plus performant
une méthode peu être plus performant pour x traitement et une autre pour y traitement...
Marsh Posté le 24-08-2003 à 01:00:49
os2 a écrit : optimisation et vb c'est pas contradictoire ça? |
ban
le VB c'est pas mal bordel !
Marsh Posté le 24-08-2003 à 12:21:58
De toute façon, il faudra utiliser Mid pour mettre ta chaîne dans un tableau, donc ça va revenir au même !
Marsh Posté le 24-08-2003 à 15:07:44
Le Castor a écrit : De toute façon, il faudra utiliser Mid pour mettre ta chaîne dans un tableau, donc ça va revenir au même ! |
Oui, c'est ce que j'ai laissé sous-entendre par mes deux questions.
Mais alors, je ne peux pas faire mieux que ce que je fais actuellement ?
Marsh Posté le 24-08-2003 à 19:18:10
charly007 a écrit : |
Pour moi, ça me convient comme ça, j'aurais fait pareil !
Marsh Posté le 25-08-2003 à 09:20:22
Pas possible de les lire en tableau d'entiers ? Ca irait peut-être plus vite. (genre lecture binaire caract par carac, une fois la structure connue (sauts de lignes au bout de n caract), même si ce sont des caractères ASCII).
Traitement de chaînes un peu lourd en VB.
On avait une manip où récupère chaîne de données (les datas de la courbe, 1024 caractères) d'un oscillo Tektro. En VB3 (16 bits), il me fallait 1 seconde pour décoder les 1024 caractères en valeur integer, ai écrit une DLL, il fallait alors 1,1 milli seconde pour faire la même chose (en C, le caractère et la valeur int, c'est direct). NB : c'était sur un PC à 25MHz ou 33 (genre 386) mais ça change pas le principe.
Marsh Posté le 25-08-2003 à 12:45:15
CARBON_14 a écrit : Pas possible de les lire en tableau d'entiers ? Ca irait peut-être plus vite. (genre lecture binaire caract par carac, une fois la structure connue (sauts de lignes au bout de n caract), même si ce sont des caractères ASCII). |
D'après ce que j'ai compris, on ne peut accéder aux éléments d'une chaîne qu'en utilisant des fonctions comme Mid.
Pour ce qui est de la dll, je veux bien essayer, mais :
- Je ne sais pas comment en écrire une de manière générale ;
- Je ne sais pas comment l'utiliser dans VBA pour Excel.
Marsh Posté le 25-08-2003 à 15:05:46
Pour la DLL, c'est juste pour dire qu'en traitement direct, ça va plus vite.
Le fichier contient UNE chaîne ou un "paquet" de chaînes ?
Le mode "binary" existe-t-il sous VBA EXCEL ? Si oui, ça permettrait de lire les caractères du fichier comme des valeurs numériques (si on rencontre les caractères 13 ou 10, c'est la fin de chaîne). Si non, bof..
En Basic/VB "classique", on fait
dim car as string*1 si on veut récupérer chaque caractère dans un caractère chaîne (de taille 1)
ou
dim iC as integer si on veut récupérer chaque caractère dans un entier
open nomfich$ for binary as #1
Get #1,,iC ou ,,car
...
close #1
Faut surveiller la fin de ligne (caractères Cr puis Lf), voir la taille du fichier avant pour savoir quand s'arrêter.
Marsh Posté le 25-08-2003 à 15:11:19
Déjà, au lieu d'utiliser Mid, utilise Mid$ (qui fait la même chose, mais traite les données non sous forme de chaîne, mais sous forme binaire directe).
Marsh Posté le 25-08-2003 à 20:13:17
Le Castor a écrit : Déjà, au lieu d'utiliser Mid, utilise Mid$ (qui fait la même chose, mais traite les données non sous forme de chaîne, mais sous forme binaire directe). |
MidB tu veux dire ?
J'ai essayé, et ça va moins vite.
Marsh Posté le 25-08-2003 à 20:16:38
CARBON_14 a écrit : Pour la DLL, c'est juste pour dire qu'en traitement direct, ça va plus vite. |
Le fichier contient des nombres compris entre 0 et 255, c'est un fichier d'image au format raw. Donc on pourrait dire une chaîne, et non un "paquet" de chaînes.
Ensuite, en ce qui concerne le mode d'ouverture, j'utilise FileSystemObject, c'est un accès séquentiel. Voici tout le code :
Code :
|
Marsh Posté le 25-08-2003 à 20:31:58
Pour "paquet de chaîne", je pensais "plus d'une chaîne dans le fichier", genre faut chercher plus d'une fois CrLf.
J'ai pas de bureautique Microsoft donc pas de VBA chez moi (trop cher !!), je regarde demain au boulot si on peut accéder à un fichier en binaire, voir si ça irait plus vite (y a de fortes chances). Je connais pas spécialement VBA, mais avec l'aide en ligne....
En s'organisant, on doit même ne pas avoir à charger tout, juste lire au vol les triplets RGB.
fichier(ind).NbPixel, c'est un compteur indexé ?
Marsh Posté le 25-08-2003 à 20:43:38
CARBON_14 a écrit : Pour "paquet de chaîne", je pensais "plus d'une chaîne dans le fichier", genre faut chercher plus d'une fois CrLf. |
Oui, j'avais bien compris. C'est une suite de nombres sans espaces ni saut de lignes.
Mais ce n'est pas le temps de lecture du fichier que je trouve long, puisque je lis 3 millions d'octets en moins d'une seconde, mais c'est plutôt le traitement de la chaine qui prend du temps, jusqu'à 15 secondes pour 3 millions d'octets.
Pour fichier(ind).NbPixel j'ai édité le code, voir au-dessus. C'est un enregistrement qui permet de stocker le nb de pixels blancs (entre autres) pour chaque fichier situé dans le dossier choisi.
PS : pour la ddl je veux bien en faire une, mais je ne sais pas très bien comment.
Marsh Posté le 25-08-2003 à 20:53:25
charly007 a écrit :
|
Tu peut déjà transformer ça en ça :
Code :
|
Plus rapide que <> true en théorie !
Marsh Posté le 25-08-2003 à 21:06:18
Désolé pour le NbPixel, je viens de voir qu'il faisait partie d'une structure.
15 secondes pour 3Moctets, c'est pas mal (le CPU doit pédaler dur).
Faut que je me trouve un fichier de 3Mo pour faire tests sous DOS voir si ce que je propose est valable..
Ca serait du genre
Dim valeur1 As Integer
Dim valeur2 As Integer
Dim valeur3 As Integer
Dim chaine As String*1
' test de principe quitte à voir si extrapolable à VBA pur et dur avec les fonctions "spéciales"
open "c:\toto\machin\chose.dat" for binary as #1
Do While not EOf(1) ' pas sûr idéal vu le mode d'accès (je veux dire vu ce qu'on lit ensuite, sais plus si protège bien de fin de fichier si on en lit 3000 ensuite et que ça tombe pas juste)
For pix = 1 To 3000 Step 3 'Lire 1000 triplets (R,G,B) à la suite VOIRE toute la longueur du fichier d'un coup vu qu'on se déplace sans stocker
Get #1,,chaine ' 1 seul caractère
valeur1 = Asc(chaine)
Get #1,,chaine
valeur2 = Asc(chaine)
Get #1,,chaine
valeur3 = Asc(chaine)
If EstBlanc(valeur1, valeur2, valeur3) Then
fichier(ind).NbPixel = fichier(ind).NbPixel + 1
End If
Next pix
Loop
Close #1
Je pense qu'il faudrait regarder la taille exacte du fichier pour tester et imposer le nombre de boucles de triplets (comme ça, pas de EOF(1) à tester) pour comparer avant de se "casser la tête" à faire mieux si ça gagne pas trop en vitesse.
Les DLL, ça fait des années que j'en ai pas écrites (toutes en 16 bits) => ai perdu pas mal, surtout que je suis pas du métier. C'était pour VB3.
Marsh Posté le 25-08-2003 à 21:18:30
Pour le NbPixel je l'ai ajouté après ton message.
Dans le code que tu proposes, tu vas effectuer des lectures une par une, donc un accès disque à chaque fois. A mon avis, ça sera pas efficace du tout.
Ce qui pose problème dans mon code, c'est le traitement de la chaine par l'utilisation de la fonction Mid. Je vais chercher encore qqch de mieux.
Marsh Posté le 25-08-2003 à 21:28:41
charly007 a écrit : Pour le NbPixel je l'ai ajouté après ton message. |
Mince, j'ai pas trop le temps de chercher là, comme ça fait 4 mois que je fait du VBA, j'pourrais trouver un truc.
Sinon, aucune autre façon de lire à partir d'une chaîne de caractère que le Mid...
Marsh Posté le 25-08-2003 à 22:08:14
Left$ extrait la partie "gauche" d'une chaîne, right$ la partie droite, mid$, une partie quelconque. Y a pas de choix ni d'alternative à Mid$ à part ruser en passant par un autre type de données.
Pour en avoir le coeur net, je fais test sur mon 100MHz vu que y a VB3 dessus. Vais bien trouver un fichier de 300k qui traîne (ça fait 3Mo sous 1GHz).
Je ne pense pas qu'il accède au disque en continu, passe tj par buffers (mais je sais plus quelle taille ils ont par défaut).
EDIT : fichier de 248 278 octets (BMP). Sous VB3 (sans compiler), lecture char par char (80 000 tours de triplets) : 29 secondes sur le 100MHz. Lecture en 8000 tours de trois chaînes de 10 caract : 2 secondes. Mais là y a plus la conversion asc() qui prend 4 secondes sur les 29.
En C, je charge tout en mémoire et je bouge les pointeurs.
Je continue tests...
EDIT 2 : 18 secondes en définissant une structure
type Triplet
R as string * 1 ' à mettre dans le bon ordre !
G as string * 1
B as string * 1
end type
dim Pixel as Triplet
On a valeur1 = asc(Pixel.R)
valeur2 = asc(Pixel.G) etc.. Ca économise les Mid$()
Autre test : en triplant la taille de la structure R1 G1 B1 R2 G2 B2 R3 G3 B3, j'arrive à 5 secondes de lecture/traitement. Ca alourdit le code mais ça va plus vite.
Je retourne à mon C, faut que j'avance pour demain, avant les vacances !!
Marsh Posté le 25-08-2003 à 23:06:59
Finalement, ça me turlupinait. Nouvel essai avec structure plus grande : 3 secondes.
avec
Type Pixel
R As String * 1
G As String * 1
B As String * 1
End Type
Type Bloc
Pnts(10) As Pixel
End Type
Dim Blok As Bloc
Dim valeur1 As Integer
Dim valeur2 As Integer
Dim valeur3 As Integer
Dim iC&, iL%
Open "D:\image1x.bmp" For Binary As #1
Beep ' pour chrono
For iC& = 1 To 8000
Get #1, , Blok
For iL% = 1 To 10
valeur1 = Asc(Blok.Pnts(iL%).R)
valeur2 = Asc(Blok.Pnts(iL%).G)
valeur3 = Asc(Blok.Pnts(iL%).B)
Next iL%
Next iC&
Close #1
Beep
En fait, faudrait adapter la taille de la structure à ce qui est lu, genre multiple de 8 triplets pour que ça tombe juste.
Marsh Posté le 29-08-2003 à 14:11:10
Tu peux essayer ca :
Code :
|
Marsh Posté le 06-09-2003 à 21:11:21
Les Get,,1 sont un peu lents (accès disque à chaque fois semble-t-il). Des blocs, c'est mieux.
Ubound(), on peut le remplacer par la valeur en "dur" vu qu'on la gère nous même. J'ai déja vu des lenteurs (en QuickBasic/DOS) avec modules écrits avec les Lbound() et Ubound() mais c'est incontournable si on écrit une fonction généraliste (!!), ici, pas le cas.
Charly007 a dû résoudre son pb, on ne le voit plus (dans ce cas, on n'aura jamais la solution) ou il a abandonné.
Marsh Posté le 07-09-2003 à 01:54:53
Non, je suis à l'écoute. Je n'ai pas donné de réponses parce que je viens de monter un 2e PC, je suis dans les réglages carburation.
Vous utilisez tous Get, mais moi j'aurais préféré utiliser FileSystemObject, qui me semble être la solution d'"avenir" préconisée par Microsoft.
Néanmoins, dès que j'aurais tout installé, je m'y remets et je regarde ce que vous m'avez conseillé.
Merci.
Marsh Posté le 07-09-2003 à 10:59:25
Ne pas trop overclocker le carburateur, des fois que la canicule revienne en hiver. J'ai dû arrêter les calculs intensifs Folding@home, mon processeur frôlait les 57°C.
Avant d'utiliser le "standard futuriste", voir quelle est la solution la plus efficace pour, APRES, si possible, regarder comment utiliser "FileSystemObject" dès fois qu'il soit détournable ou adaptable, voire qu'il y ait un analogue d'accès "binaire".
Les fichiers INI sont obsolètes à l'idée Krosoft : que Base de Registre. Je les utilise à tour de bras, logés dans le répertoire où est l'appli avec les DLL spécifiques => très propre car éliminé en supprimant simplement le répertoire. Obsolètes mais utiles car souples.
Je rentre de congés hier, donc pas eu occasion regarder si FileSystemObject peut quand même servir
Set f3 = f2.opentextfile(f1.Path, ForReading) // Reading que chaîne ? Binaire possible ?
Do While f3.AtEndOfStream <> True
chaine = f3.read(3000) // peut-on lire un BLOC genre 8 triplets de pixels d'un coup ?
Tester les codes proposés en ouvrant directement un fichier connu permet déjà de mesurer le gain de rapidité. On verra après si extensibilité moderne possible.
Pour les chaînes, je pense pas, qu'à part avec DLL si acceptée par le système, qu'on puisse accélérer beaucoup le traitement. Mes DLL VB3/Win3.11, c'est vieux (on perd vite, je fais plus de VB). Si possible lire "en bloc" par blocs, ça devrait "speeder" (? ).
EDIT : en googlant, j'ai la crainte que MST ne sache gérer que les fichiers texte. Cf spécialiste de Microsoft Scripting Technologie ? Sinon, shell vers un prog écrit en langage plus adapté qui ferait le travail "à côté".
Marsh Posté le 11-09-2003 à 15:58:51
Ma méthode marche trés bien.
C'est pas la lecture du fichier qui est longue mais le traitement.
Dans mon exemple je travaille avec des tableaux qui est beaucoup plus rapide que des chaines.
Marsh Posté le 11-09-2003 à 16:25:13
On arrive à converger vers le fait que lire des chaînes, pas de pb : rapide, en bloc.
Découper des chaînes en petits bouts, long.
C'est pourquoi, vu ce qu'il veut faire, vaut mieux lire des byte, integer, truc qq qui représente directement le point à lire. Un par un, bloc par bloc, faut comparer (àa me fait gagner un temps fou de lire par bloc de 8*3 au lieu de 1 à la fois, ça peut aussi dépendre du système, je travaille sous DOS ou win 16 bits, en 32, y a eu des améliorations (heureusement !!))
Marsh Posté le 12-09-2003 à 13:34:22
Sans être sûr que cela pourra aider, voici un lien vers un site d'optimisation du code VB.
http://www.vb2themax.com/SearchKey.asp?PageID=Optimize
Marsh Posté le 12-09-2003 à 13:48:35
comment charger un fichier binaire directement dans un tableau de bytes:
Code :
|
Marsh Posté le 12-09-2003 à 14:01:50
Spark a écrit : |
non C de la merde
pour ce ki est du pb ya bien mieux que les mid si les chaines sont de longueur fixe.
tu défini une structure du style :
Public Type Entete240 |
et tu copies ta chaine dedans en faisant :
|
Marsh Posté le 12-09-2003 à 14:19:12
ah tiens CopyMemory, impossible de s'en passer si on veut des performances valables
pis avec ça, pas besoin de faire une DLL
Marsh Posté le 12-09-2003 à 14:37:50
drasche a écrit : ah tiens CopyMemory, impossible de s'en passer si on veut des performances valables |
beh de toute façon perf avec VB = API win
et je peux pas rajouter trop de DLL donc....
Marsh Posté le 23-08-2003 à 19:01:51
Je lis un fichier texte dans une chaine de caractère.
Pour optimiser les accès disque, je lis un grand nombre de caractères.
Après je dois parcourir la chaine entièrement et faire un traitement sur chaque caractère.
Le code (ça compte le nb de pixels blancs dans un fichier raw (pix correspond en fait à un photophore)) :
Je pense qu'il y a mieux que l'utilisation de la fonction Mid.
Peut-être qu'en déplaçant la chaine dans un tableau ? Mais si c'est pour utiliser Mid pour le faire ?
Merci.
Message édité par charly007 le 23-08-2003 à 19:02:58