Help !! bin2hex avec multi-threading !! Urgent !!

Résolu
XelectroX Messages postés 209 Date d'inscription samedi 11 novembre 2000 Statut Membre Dernière intervention 6 novembre 2009 - 8 août 2008 à 10:18
nhervagault Messages postés 6063 Date d'inscription dimanche 13 avril 2003 Statut Membre Dernière intervention 15 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 ...

Merci à tous

19 réponses

nhervagault Messages postés 6063 Date d'inscription dimanche 13 avril 2003 Statut Membre Dernière intervention 15 juillet 2011 37
8 août 2008 à 12:08
Salut ,

Apres une simple recherche sur internet
Je tombe sur
il te reste plus qu'a convertir avec
http://tools.codes-sources.com/

J'ai pas lu ton code mais la manipukation de string est tres longue
il faut travailler au niveau bytes

Voila


static string hex2bin(string hexdata)

{

if (hexdata == null)

throw new ArgumentNullException("hexdata");

if (hexdata.Length % 2 != 0)

throw new ArgumentException("hexdata should have even length");


byte[] bytes = new byte[hexdata.Length / 2];

for (int i = 0; i < hexdata.Length; i += 2)

bytes[i / 2] = (byte) (HexValue(hexdata[i]) * 0x10

+ HexValue(hexdata[i + 1]));

return Encoding.GetEncoding(1252).GetString(bytes);

}


static int HexValue(char c)

{

int ch = (int) c;

if (ch >= (int) '0' && ch <= (int) '9')

return ch - (int) '0';

if (ch >= (int) 'a' && ch <= (int) 'f')

return ch - (int) 'a' + 10;

if (ch >= (int) 'A' && ch <= (int) 'F')

return ch - (int) 'A' + 10;

throw new ArgumentException("Not a hexadecimal digit.");

}

et


> public static string bin2hex(string bindata)

> {

> byte[] bytes =

> Encoding.GetEncoding(1252).GetBytes(bindata);

> string hexString = "";

> for (int ii = 0; ii < bytes.Length; ii++)

> {

> hexString += bytes[ii].ToString("x2");

> }

> return hexString;

> }
3
Kevin.Ory Messages postés 840 Date d'inscription mercredi 22 octobre 2003 Statut Membre Dernière intervention 7 janvier 2009 11
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.

Voilà
3
Kevin.Ory Messages postés 840 Date d'inscription mercredi 22 octobre 2003 Statut Membre Dernière intervention 7 janvier 2009 11
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
3
XelectroX Messages postés 209 Date d'inscription samedi 11 novembre 2000 Statut Membre Derniè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 ...
0

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

Posez votre question
nhervagault Messages postés 6063 Date d'inscription dimanche 13 avril 2003 Statut Membre Dernière intervention 15 juillet 2011 37
8 août 2008 à 14:14
Pour le faire en multithreading ???
Ca sert a rien de se compliquer pour des choses aussi simple.

Regardes du coté du backgroundworker, il repond peut etre a la question

NB : Evites urgent dans Titre ,-)
0
XelectroX Messages postés 209 Date d'inscription samedi 11 novembre 2000 Statut Membre Dernière intervention 6 novembre 2009
8 août 2008 à 15:48
Ok, ben merci pour tout :)
0
nhervagault Messages postés 6063 Date d'inscription dimanche 13 avril 2003 Statut Membre Dernière intervention 15 juillet 2011 37
8 août 2008 à 15:55
Pourquoi tu ne reponds   pas à la question du multithreading ?
C'était une mauvaise piste ??
0
XelectroX Messages postés 209 Date d'inscription samedi 11 novembre 2000 Statut Membre Derniè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)
0
nhervagault Messages postés 6063 Date d'inscription dimanche 13 avril 2003 Statut Membre Dernière intervention 15 juillet 2011 37
8 août 2008 à 17:40
Voila un article sur le multithreading a toi d'en faire bon usage

http://www.dotnetguru.org/articles/dossiers/threads/multithreading.htm
0
XelectroX Messages postés 209 Date d'inscription samedi 11 novembre 2000 Statut Membre Derniè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 ?
0
nhervagault Messages postés 6063 Date d'inscription dimanche 13 avril 2003 Statut Membre Dernière intervention 15 juillet 2011 37
8 août 2008 à 19:09
Fais une  recherche sur internet et tu trouves ;-)

exemple : http://glarde.developpez.com/dotnet/bgworker/vb/

C'est pas dur.

Tes watch sont a mettre en dehors de la boucle et pas dedans
car le code dans la boucle a une durée infine
lecture + conversion

le temps en milliseconde --> surement 0
0
Kevin.Ory Messages postés 840 Date d'inscription mercredi 22 octobre 2003 Statut Membre Dernière intervention 7 janvier 2009 11
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).
0
XelectroX Messages postés 209 Date d'inscription samedi 11 novembre 2000 Statut Membre Dernière intervention 6 novembre 2009
8 août 2008 à 19:53
Ok alors la, merci à vbfrance et surtout à toi
J'ai plus qu'à l'arranger à ma sauce
0
nhervagault Messages postés 6063 Date d'inscription dimanche 13 avril 2003 Statut Membre Dernière intervention 15 juillet 2011 37
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.

Bon coding
0
Kevin.Ory Messages postés 840 Date d'inscription mercredi 22 octobre 2003 Statut Membre Dernière intervention 7 janvier 2009 11
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
0
nhervagault Messages postés 6063 Date d'inscription dimanche 13 avril 2003 Statut Membre Dernière intervention 15 juillet 2011 37
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."

string b = "h";
b += "ello";
0
Kevin.Ory Messages postés 840 Date d'inscription mercredi 22 octobre 2003 Statut Membre Dernière intervention 7 janvier 2009 11
8 août 2008 à 21:37
OK, merci pour l'info

Bonne continuation...
0
yoankiller Messages postés 1 Date d'inscription samedi 6 septembre 2008 Statut Membre Derniè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!!
0
nhervagault Messages postés 6063 Date d'inscription dimanche 13 avril 2003 Statut Membre Dernière intervention 15 juillet 2011 37
7 sept. 2008 à 00:32
@yoankiller

Bonjour,

STP lit le réglement
Evites de parler le langage SMS, et pose une question clair, dans un autre post.
Et avant cherche sur internet une réponse.

Ta question n'est pas claire et surtout  est trop général et n'a rien a voir
avec le post.
0
Rejoignez-nous