Avatar billede KLS Novice
14. januar 2009 - 21:46 Der er 22 kommentarer og
1 løsning

Threading kan det være en gevinst ? og hvordan

Hej jeg sider og arbejder med en Application
(Windows Form Application)
Hvor jeg har en del tunge fil funktioner, som henter en fil, sortere i den, og derefter skriver til en ny fil.

Kan jeg have nogen gavn at at lade en selvstændig Thread tage sig af de funktioner, og hvordan gør jeg dette ? Jeg er ny i forhold til at arbejde med Threads, og derfor kan det være at dette spørgsmål lyde en smule dumt, eller fjollet, men kunne godt tænke mig at lave en så hurtig input/filhåndterings funktion som muligt i mit program.
Avatar billede arne_v Ekspert
14. januar 2009 - 21:56 #1
Hvis du laver tungt arbejde i event traaden saa fryser din GUI.

Saa det lyder da absolut som en oplagt mulighed at bruge en traad,
Avatar billede KLS Novice
14. januar 2009 - 22:06 #2
Korrekt min GUI hænger i op til 10 sec når den laver hent, rediger, sorter skriv funktionen.
Avatar billede arne_v Ekspert
14. januar 2009 - 22:11 #3
Saa er der doemt traad !
Avatar billede KLS Novice
14. januar 2009 - 22:12 #4
Men jeg har Ingen kendskab til Thread programmering eller brug af threads.
Da jeg aldrig har lavet programmer hvor flere rutiner har skulle køre samtidig eller at det har fået mit program til at hænge fast før.

Så helt basal start hjælp er nødvendig.
Avatar billede arne_v Ekspert
14. januar 2009 - 22:23 #5
Jeg har et download eksempel liggende paa lager - maaske kan de inspirere:

Imports System
Imports System.Drawing
Imports System.IO
Imports System.Net
Imports System.Windows.Forms
Imports System.Threading

Public Class MainForm
Inherits Form
    Private bar As ProgressBar
    Private start As Button
    Private abort As Button
    Private t As Thread

    Public Sub New()
        bar = New ProgressBar
        start = New Button
        abort = New Button
        SuspendLayout
        bar.Location = New Point(50, 50)
        bar.Size = New Size(200, 50)
        bar.Name = "Progress Bar"
        start.Location = New Point(50, 150)
        start.Size = New Size(200, 50)
        start.Name = "Start Button"
        start.Text = "Start"
        AddHandler start.Click, AddressOf StartClick
        abort.Location = New Point(50, 250)
        abort.Size = New Size(200, 50)
        abort.Name = "Abort Button"
        abort.Text = "Abort"
        AddHandler abort.Click, AddressOf AbortClick
        ClientSize = New Size(300, 350)
        Controls.Add(bar)
        Controls.Add(start)
        Controls.Add(abort)
        Name = "Main Form"
        Text = "Main Form"
        ResumeLayout(False)
    End Sub
    Sub ResetBar(ByVal n As Integer)
        bar.Minimum = 0
        bar.Maximum = n
        bar.Value = 0
    End Sub
    Sub UpdateBar(ByVal n As Integer)
        bar.Value = n
    End Sub
    Delegate Sub ResetHandler(ByVal n As Integer)
    Delegate Sub UpdateHandler(ByVal n As Integer)
    Sub Copy()
        Try
        Dim req As HttpWebRequest = CType(WebRequest.Create("http://wasd.vsm.com.au/wasd/htroot913.zip"), HttpWebRequest)
        Dim resp As HttpWebResponse = CType(req.GetResponse, HttpWebResponse)
        Dim tot As Integer = CType(resp.ContentLength, Integer)
        If bar.InvokeRequired Then
            bar.Invoke(New ResetHandler(AddressOf ResetBar), New Object() {tot})
        Else
            ResetBar(tot)
        End If
        Dim f1 As Stream = resp.GetResponseStream
        Dim f2 As Stream = New FileStream("C:\htroot913.zip", FileMode.CreateNew, FileAccess.Write)
        Dim sofar As Integer = 0
        Dim b(1000) As Byte
        Dim n As Integer
        n = f1.Read(b, 0, b.Length)
        While n > 0
            f2.Write(b, 0, n)
            sofar += n
            If bar.InvokeRequired Then
                bar.Invoke(new UpdateHandler(AddressOf UpdateBar), New Object() {sofar})
            Else
                UpdateBar(sofar)
            End If
            n = f1.Read(b, 0, b.Length)
        End While
        f2.Close
        f1.Close
        resp.Close
        Catch ex As Exception
        MessageBox.Show(ex.Message)
        End Try
    End Sub
    Sub StartClick(ByVal sender As Object, ByVal e As EventArgs)
        t = New Thread(AddressOf Copy)
        t.Start
    End Sub
    Sub AbortClick(ByVal sender As Object, ByVal e As EventArgs)
        t.Abort
    End Sub
    <STAThread()> _
    Public Shared Sub Main(ByVal args As String())
        Application.Run(New MainForm)
        Application.Exit
        Environment.Exit(0)
    End Sub
End Class
Avatar billede KLS Novice
14. januar 2009 - 22:26 #6
Arne har du mulighed for at bare fortælle lidt mere om hvordan jeg gør med thread. men hvis jeg har forstået det ret, så skal jeg lave en handle, for hver funktion, som jeg ønsker der skal bruge en Thread ?

og når jeg så skal starte min funktion, så kalder jeg den med Thread istedet for selve min funktion / sub ?
Avatar billede KLS Novice
14. januar 2009 - 22:29 #7
Jeg kan da også sige at filen jeg starter med at behandle fylder 1.5 Mb og jeg får den kogt ned til det rigtige format, med det jeg skal bruge så fylder den kun 378 Kb.
Så det er en hel masse Replace og Regex kald den bruger, og det er nok også det der er med til at gøre det tungt.
Avatar billede arne_v Ekspert
14. januar 2009 - 22:52 #8
Du skal have en traad og en funktion for hver ting du oensker at starte i parallel.
Avatar billede KLS Novice
14. januar 2009 - 22:57 #9
oki jeg vil se om jeg ikke kan få det til at virke ud fra det som du har givet mig indtil videre, men jeg venter lidt med at lukke, før jeg har tastet mig til noget som enten virker eller ikke virker, og Arne, kan godt være at jeg skal bruge din ekspertise senere til noget mere.. :)
Avatar billede KLS Novice
15. januar 2009 - 18:43 #10
Jeg syntes jeg har lidt svært ved lige at komme igang med Thread.
Men nu vil jeg lige prøve at sidde og rodde lidt med det og se om jeg ikke kan komme igang med det af mig selv efter dit eksempel, også tager jeg den derfra.
Avatar billede KLS Novice
16. januar 2009 - 01:08 #11
Jeg bliver gråhåret inden jeg får der her til at virke.

Jeg får en fejl når det er at jeg prøver at skrive til en textbox, så får jeg fejlen at den ikke er en del af den thread, og nej hvor er det bare svært at starte på noget ny... fustration efter fustration.
Avatar billede arne_v Ekspert
16. januar 2009 - 01:56 #12
Kig på den Invoke teknik jeg bruger i koden til at opdatere progress bar'en med !
Avatar billede KLS Novice
20. januar 2009 - 15:55 #13
Tak Arne jeg kigger lige lidt mere på det :)

Men smid et svar så får du lige point til at starte med, for jeg er sikker på at jeg nok skal få det til at virke.

Men vi er enige om at alle ting, som skal interacte med noget, der skal jeg lave en Invoke hvis det ikke er en del af Thread ?
Avatar billede KLS Novice
20. januar 2009 - 19:39 #14
For at jeg kan komme igang må jeg nok være lidt mere konktret omkring min source kode :

jeg har følgende Sub's :
Private Sub Get_A(ByVal Valg As String)

Private Sub Slet_fil(ByVal Filnavn As String, ByVal Bib As String)
Private Sub Skriv_fil(ByVal Navn As String, ByVal Indhold As String)
Private Sub Skriv_XML(ByVal Navn As String, ByVal Indhold As String)

Get_A bliver kaldt fra flere knapper med forskellige værdier, alt efter hvad det er for et valg den skal hente

sidst i Get_A kaldes Skriv_fil(Valg & "_" & Klokken, txtr2)
sidst i Skriv_fil kaldes Fil_conv(Navn & ".txt")

Det der får min GUI til at fryse er Get_A, hvor jeg laver en del oprydning i en fil, og laver noget omformatering, så en fil der starter med at fylde 1.5 Mbyte kommer ned at fylde 332 KB.

Get_A skriver undervejs også nogle output til en textbox i min GUI, men hvis jeg laver det med Thread får jeg en fejl, når jeg skal til at skrive output til min textbox1.text

Hvordan kan jeg gøre dette, og hvordan er det smartes at jeg strukturere min kode.
Avatar billede KLS Novice
20. januar 2009 - 19:42 #15
Målet med mit program er at den automatisk en gang i minuttet henter en automatisk genereret fil, og laver den samme konvertering af indholdet, samtidig med at programmet kan bruges til at brugeren kan foretage andre valg, og bruge andre funktioner, mens at Get_A kører i baggrunden, helt af sig selv.
Avatar billede arne_v Ekspert
21. januar 2009 - 02:26 #16
Hvis du skal opdatere en kontrol fra andet end event tråde f.eks. fra en tråd som du selv har
startet så skal du bruge Invoke.

Lad sub Get_A starte en tråd og lad den opdatere undervejs via Invoke.
Avatar billede arne_v Ekspert
21. januar 2009 - 02:26 #17
Og et svar.
Avatar billede arne_v Ekspert
21. januar 2009 - 02:27 #18
Altså Get_A kører du i event tråden men Get_A starter så en tråd med Get_RealA som
gør arbejdet.
Avatar billede KLS Novice
21. januar 2009 - 17:00 #19
Oki tror jeg har forstået det meste nu :)

Du får dine point, men jeg fortsætter nok med lidt spørgsmål her hvis jeg føler det stadig er nødvendigt (det er rarest at have det samlet et sted istedet der bliver linket til flere forskellige, og ja, hvis det så er mere kompliceret bliver der oprettet en ny tråd til point og spørgsmål.
Avatar billede arne_v Ekspert
22. januar 2009 - 03:10 #20
helt fint
Avatar billede KLS Novice
23. januar 2009 - 22:55 #21
Det har forbedret performance både med hastighed og oplevelse fra bruger siden.

Tror den håndtere et enkelt fil kald nu på omkring 5 sekunder inkl hentning af filen.
Avatar billede KLS Novice
23. januar 2009 - 22:56 #22
Så jeg har fået det til at virke nu, men mangler bare det med at den opdatere GUI undervejs, men det skal jeg nok kæmpe mig igennem :)
Avatar billede arne_v Ekspert
24. januar 2009 - 03:25 #23
Det er bare at lave invoke tricket.

Jeg har et eksempel mere på lageret:

Imports System
Imports System.Threading

Public Class Form1
    Private done As Boolean
    Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
        done = False
        Dim t As Thread = New Thread(AddressOf TextUpdateThread)
        t.Start()
    End Sub
    Private Sub Button2_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button2.Click
        done = True
    End Sub
    Private Sub TextUpdateThread()
        Dim i As Integer = 0
        While Not done
            i = i + 1
            If TextBox1.InvokeRequired Then
                TextBox1.Invoke(New TextUpdateHandler(AddressOf TextUpdate), New Object() {i})
            Else
                TextUpdate(i)
            End If
            Thread.Sleep(1000)
        End While
    End Sub
    Private Delegate Sub TextUpdateHandler(ByVal n As Integer)
    Private Sub TextUpdate(ByVal n As Integer)
        TextBox1.Text = n.ToString()
    End Sub
End Class
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester