XelectroX
Messages postés209Date d'inscriptionsamedi 11 novembre 2000StatutMembreDernière intervention 6 novembre 2009
-
8 août 2008 à 10:18
nhervagault
Messages postés6063Date d'inscriptiondimanche 13 avril 2003StatutMembreDernière intervention15 juillet 2011
-
7 sept. 2008 à 00:32
Bonjour,
Je cherche quelqu'un qui serait capable de me faire fonctionner cela correctement (problème décrit à la fin) :
Public Class bin2hex
Dim processes As Process
Dim Thread1 As System.Threading.Thread
Dim Thread2 As System.Threading.Thread
Private Sub Open_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Open.Click
OFD.InitialDirectory = My.Application.Info.DirectoryPath
OFD.ShowDialog()
txtIN.Text = OFD.FileName
End Sub
Private Sub Save_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Save.Click
SFD.FileName = txtIN.Text & ".hex"
SFD.ShowDialog()
txtOUT.Text = SFD.FileName
End Sub
Private Sub Process_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Process.Click
Dim input() As Byte = IO.File.ReadAllBytes(txtIN.Text)
Dim output As String = ""
PB.Visible = True
PB.Maximum = input.Length + 2
processes = New Process(input)
CheckForIllegalCrossThreadCalls = False
AddHandler processes.Progress, AddressOf progress
Thread1 = New System.Threading.Thread(AddressOf processes.thread1)
Thread1.Start()
Thread2 = New System.Threading.Thread(AddressOf processes.thread2)
Thread2.Start()
End Sub
Sub progress(ByVal pos As Long)
Try
PB.Value = pos
Speed1.Text = "Thread1 : " & Int(processes.totalcalc1 / processes.totaltime1) & "calc/ms"
Speed2.Text = "Thread2 : " & Int(processes.totalcalc2 / processes.totaltime2) & "calc/ms"
Catch
End Try
Application.DoEvents()
If pos >= processes.input.Length - 1 Then
IO.File.WriteAllText(txtOUT.Text, processes.output)
Try
If My.Application.CommandLineArgs(0) <> ""And My.Application.CommandLineArgs(1) <> ""Then End
Catch
End Try
MsgBox("Finished !", MsgBoxStyle.Information)
PB.Visible = False
Thread1.Abort()
Thread2.Abort()
End If
End Sub
Private Sub bin2hex_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Try
If My.Application.CommandLineArgs(0) <> ""And My.Application.CommandLineArgs(1) <> ""Then
txtIN.Text = My.Application.CommandLineArgs(0)
txtOUT.Text = My.Application.CommandLineArgs(1)
My.Application.DoEvents()
Process_Click(sender, e)
End If
Catch
End Try
End Sub
End Class
Public Class process
Public input() AsByte
Public output() AsChar
Public working1 AsBoolean
Public working2 AsBoolean
Dim watch1 As New Diagnostics.Stopwatch
Dim watch2 As New Diagnostics.Stopwatch
Public totaltime1 As Long
Public totaltime2 As Long
Public totalcalc1 As Long
Public totalcalc2 As Long
Dim pos As Long = -1
Sub New(ByVal _input() As Byte)
input = _input
ReDim output(((input.Length - 1) * 2) + 1)
End Sub
Sub thread1()
While pos < input.Length - 1
working1 = True
pos += 1
watch1.Reset()
watch1.Start()
Dim MyPos As Long = pos
Dim hexa As String = Hex(input(MyPos))
If hexa.Length < 2 Then
output(MyPos * 2) = "0"
output((MyPos * 2) + 1) = hexa
Else
output(MyPos * 2) = Mid(hexa, 1, 1)
output((MyPos * 2) + 1) = Mid(hexa, 2, 1)
End If
watch1.Stop()
totaltime1 += watch1.ElapsedMilliseconds
totalcalc1 += 1
RaiseEvent Progress(pos)
working1 = False
End While
End Sub
Sub thread2()
While pos < input.Length - 1
working2 = True
pos += 1
watch2.Reset()
watch2.Start()
Dim MyPos As Long = pos
Dim hexa As String = Hex(input(MyPos))
If hexa.Length < 2 Then
output(MyPos * 2) = "0"
output((MyPos * 2) + 1) = hexa
Else
output(MyPos * 2) = Mid(hexa, 1, 1)
output((MyPos * 2) + 1) = Mid(hexa, 2, 1)
End If
watch2.Stop()
totaltime2 += watch2.ElapsedMilliseconds
totalcalc2 += 1
RaiseEvent Progress(pos)
working2 = False
End While
End Sub
Public Event Progress(ByVal pos As Long)
End Class
J'explique mon problème, en fait mon fichier de sortie semble être bon mais contient des vides
Si quelqu'un saurait aussi me l'optimiser car j'ai des fichiers de plus en plus conséquents à traiter ...
Kevin.Ory
Messages postés840Date d'inscriptionmercredi 22 octobre 2003StatutMembreDernière intervention 7 janvier 200911 8 août 2008 à 17:51
Salut,
"Un backgroundworker n'est qu'un seul thread"
Si t'en veux deux, tu en créé deux, tout simplement
C'est très facile à utiliser, et c'est parfait pour ton cas.
Après, si ton code est lent, c'est principalement à cause de l'appel de l'événement Progress. Ton thread de calcul va attendre que le thread principal aie affiché la progression avant de continuer => Super lent. Evite de le faire à chaque byte, mais fais le après 1000 (voir plus) bytes convertis par exemple.
Tu as deux thread dans ton code, mais après avoir regardé le code vite fais, j'ai l'impression que les deux thread font exactement la même chose? (tout le travail à double) Je pense qu'un seul thread séparé est largement suffisant.
Tes watch1.Reset(), watch1.Start() et watch1.Stop() te prennent aussi beaucoup de temps. Ne fais pas comme ça.
Je ne connais pas la fonction Hex. Mais je sais qu'on peut appeler la fonction ToString avec un paramètre "h" pour convertir en hexa, peut-être est ce plus rapide?
Alors comment faire? Tourne dans ton 2ème thread le plus vite possible pour faire ta conversion, tu ne fais que d'incrémenté une variable pour indiquer la progression. C'est dans ton thread principal, grâce à un Timer qui vient régulièrement (toute les secondes par ex) "voir" ta variable de progression que tu devrais faire le calcul pour savoir quel à été le temps de calcul (Temps/Progression) et afficher la progression.
Kevin.Ory
Messages postés840Date d'inscriptionmercredi 22 octobre 2003StatutMembreDernière intervention 7 janvier 200911 8 août 2008 à 19:27
Oui, c'est possible
Je viens juste de créer ce que tu veux faire (avec un backgroundworker, une indication de progression, un calcul du temps total pour la conversion, mais sans afficher le résultat)
Cette méthode n'est viable que pour de petits fichiers (<10 MB), impossible de convertir un DivX sur mon PC, je n'ai pas assez de mémoire. Pour convertir de gros fichiers, il faut faire ça par paquets pour éviter de tout dévoir charger en mémoire en même temps.
Un formulaire avec un bouton (btnGo), une bar de progression (prgBar) et un label (lblStatus)
Voilà le code:
Private StartTime As Date
Private WithEvents Worker As New System.ComponentModel.BackgroundWorker
Private Sub btnGo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGo.Click
Dim dlg As New OpenFileDialog
If dlg.ShowDialog = Windows.Forms.DialogResult.OK Then
StartTime = Now
lblStatus.Text = "Début de la conversion..."
btnGo.Enabled = False
Worker.WorkerReportsProgress = True
Worker.RunWorkerAsync(dlg.FileName)
End If
End Sub
Private Sub Worker_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles Worker.DoWork
Dim steps As Integer = 0
Dim file As String = e.Argument
Dim bytes() As Byte = IO.File.ReadAllBytes(file)
Dim res(bytes.Length - 1) As String
For i As Integer = 0 To bytes.Length - 1
steps += 1
If steps >= 100000 Then
Worker.ReportProgress(100 * i / bytes.Length)
steps = 0
End If
res(i) = bytes(i).ToString("X")
Next
Worker.ReportProgress(100)
e.Result = res
End Sub
Private Sub Worker_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles Worker.ProgressChanged
Me.prgBar.Value = e.ProgressPercentage
lblStatus.Text = "Conversion " & e.ProgressPercentage & "%"
End Sub
Private Sub Worker_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles Worker.RunWorkerCompleted
Dim res() As String = e.Result
btnGo.Enabled = True
Dim TotalBytes As Integer = res.Length
Dim TotalTime As Double = (Now - StartTime).TotalSeconds
lblStatus.Text = TotalBytes.ToString("###,###,##0") & " octets convertis en " & TotalTime.ToString("0.###") & " secondes (" & (TotalBytes / TotalTime).ToString("###,###,##0") & " octets/secondes)"
End Sub
Et voilà à quoi ça ressemble:
Conversion à plus de 1MB par secondes sur mon Athlon XP 2000+ datant de 2002
XelectroX
Messages postés209Date d'inscriptionsamedi 11 novembre 2000StatutMembreDernière intervention 6 novembre 2009 8 août 2008 à 14:05
C'est déjà pas mal mais y aurait-il moyen de l'avoir en multi-threading ? Quelqu'un saurait comment faire ?
Sinon, reste plus qu'a le remettre en VB.NET ...
Vous n’avez pas trouvé la réponse que vous recherchez ?
XelectroX
Messages postés209Date d'inscriptionsamedi 11 novembre 2000StatutMembreDernière intervention 6 novembre 2009 8 août 2008 à 16:32
J'ai pas essayé car mon but était de faire travailler les 2 core du processeur pour arriver à presque doubler la vitesse de calcul
Un backgroundworker n'est qu'un seul thread (d'ailleurs je ne sais même pas comment on l'utilise ni si on peut en utiliser 2) sinon, comme j'avais fait au début, j'avais des restes non calculés.
Je suis revenu au système basique (malgré qu'il faut 1 à 2 minutes pour un fichier de 512k)
XelectroX
Messages postés209Date d'inscriptionsamedi 11 novembre 2000StatutMembreDernière intervention 6 novembre 2009 8 août 2008 à 18:11
Voilà, j'ai trouvé une idée ...
Je vais faire un thread qui va calculer la moitier du fichier, et un second pour l'autre moitier.
Je vais utiliser un timer réglé à 250ms(ou 500 si ca va plus vite) pour afficher la moyenne de vitesse de chaque thread
Y aurait-il moyen d'avoir un exemple de fonctionnement du backgroundworker ?
Kevin.Ory
Messages postés840Date d'inscriptionmercredi 22 octobre 2003StatutMembreDernière intervention 7 janvier 200911 8 août 2008 à 19:33
Heu, j'ajoute que c'est ToString("X") ou ToString("x") pour convertir en hexa, et pasToString("h") comme je l'ai dis avant...
Et on peut gagner un peu de temps si on affiche pas la progression (entre 0 et 25% suivant les cas).
nhervagault
Messages postés6063Date d'inscriptiondimanche 13 avril 2003StatutMembreDernière intervention15 juillet 201137 8 août 2008 à 19:59
Tu peux gagner en temps et en clareté
Je sais que ton programme a été vite fait mais ca peut donnée des idées d'optimisation
En remplaçant
steps += 1
If steps >= 100000 Then
par un modulo
if (i mod 100000 =0) then --> tous les i divisible par 100000
--> une variable de moins et un opération d'ajout de moins
La taille du fichier étant connue on peut faire
taille / 100 ou /1000 et remplacé 100000 par le nombre.
Sinon (pour info)
--> Tu peux gérer les string avec string.format ( "Conversion {0} %" , e.ProgressPercentage)
à la place de "Conversion " & e.ProgressPercentage & "%"
--> Evite la création de 3 chaines a chaque écriture du texte conversion la classe string était immuable.
C'est une habitude a prendre pour les problème d'internationalisation aussi et de configuration.
Kevin.Ory
Messages postés840Date d'inscriptionmercredi 22 octobre 2003StatutMembreDernière intervention 7 janvier 200911 8 août 2008 à 20:31
Pas de quoi XelectroX
[auteur/NHERVAGAULT/84425.aspx nhervagault] >
"if (i mod 100000 = 0) then --> tous les i divisible par 100000 --> une variable de moins et un opération d'ajout de moins"
Au niveau clarté du code, c'est sûr, Mais au niveau perf, ça prend pas du temps de faire un modulo pour chaque octet? (à chaque itération de la boucle?)
"La taille du fichier étant connue on peut faire taille / 100 ou /1000 et remplacé 100000 par le nombre."
Ouais, mais en même temps, la conversion de 100ko est tellement rapide qu'on ne le voit même pas à l'affichage. Mais cela peut être utile lorsque on convertis de gros fichiers, mais mon code n'est de toute façon pas adapté pour ça. Le plus logique est de faire 100 pas (pas = taille / 100) quel que soit la taille du fichier si la ProgressBar va de 0 à 100 comme dans mon cas.
"Tu peux gérer les string avec string.format ( "Conversion {0} %" , e.ProgressPercentage) à la place de "Conversion " & e.ProgressPercentage & "%""
Pas faux
"Evite la création de 3 chaines a chaque écriture du texte conversion la classe string était immuable."
J'ai pas compris
nhervagault
Messages postés6063Date d'inscriptiondimanche 13 avril 2003StatutMembreDernière intervention15 juillet 201137 8 août 2008 à 20:59
Je ne sais pas pour les performance d'un modulo et une comparaison
par rapport a une addition et une comparaison
Sinon pour les classes immuables comme string
Extrait de la MSDN
Les chaînes sont immuables – le contenu d'un objet chaîne ne
peut pas être modifié une fois que l'objet a été créé, même si la
syntaxe peut laisser croire que la modification est possible. Par
exemple, lorsque vous écrivez le code ci-après, le compilateur crée
réellement un objet chaîne pour contenir la nouvelle séquence de
caractères, et la variable b continue à détenir "h."
yoankiller
Messages postés1Date d'inscriptionsamedi 6 septembre 2008StatutMembreDernière intervention 6 septembre 2008 6 sept. 2008 à 23:20
allo,
j arrais une petit question moi j ai un jeu et je veu que lordi jou tousel XD lol quelle programe qui peu lire un group de donner envoyer...merci!!