none
Threading

    Frage

  • Hallo Leute,
    ich habe eine Frage zum Threading.
    Ich möchte, wenn die Funktion 'Summe' aufgerufen wird, das die beiden Subs 'GetWert1 und 2'
    jeweils in einem eigenem Thread gestartet werden und erst wenn beide die Berechnung abgeschlossen haben, dann sollen beide addiert werden und die Funktion 'Summe' das Ergebnis zurückliefern.
    Wie stelle ich das am besten an?

    Vielen Dank im Voraus
    Christian Tauschek

            Public Function Summe() As Double
                Dim Wert1, Wert2 As Double
    
                Wert1 = GetWert1()
                Wert2 = GetWert2()
    
                Return Wert1 + Wert2
            End Function
    


    Christian Tauschek

    Mittwoch, 13. Februar 2013 14:24

Antworten

  • Hallo Christian,

    im einfachen Falle starte zwei Tasks und Addiere deren Ergebnis:

    Public Class TaskSumResults
        Public Shared Sub Run()
            Dim c As New TaskSumResults()
            Console.WriteLine("Ergebnis: " & c.Summe)
        End Sub
    
        Public Function Summe() As Double
            Dim Wert1 = Task.Factory.StartNew(AddressOf GetWert1)
            Dim Wert2 = Task.Factory.StartNew(AddressOf GetWert2)
    
            Return Wert1.Result + Wert2.Result
        End Function
    
        Private Function GetWert1() As Double
            Threading.Thread.SpinWait(100000)
            Console.WriteLine("GetWert1 completed")
            Return 41
        End Function
    
        Private Function GetWert2() As Double
            Threading.Thread.SpinWait(50000)
            Console.WriteLine("GetWert2 completed")
            Return 42
        End Function
    End Class

    Weiteres siehe Aufgabenparallelität (Task Parallel Library)

    Gruß Elmar

    Mittwoch, 13. Februar 2013 18:28
    Beantworter
  • Hallo Christian,

    ich hatte gehofft, das käme nicht - eher die Frage nach Async/Await ;)

    Unter .NET 2.0/3.5 muss man mehr tun und das Ganze grob umgeschrieben sähe so aus:

    Public Class ThreadPoolSumResults
        Public Shared Sub Run()
            Dim c As New ThreadPoolSumResults()
            Console.WriteLine("Ergebnis: " & c.Summe)
        End Sub
    
        Public Function Summe() As Double
            Dim parameter1 = New Parameter() With {.Done = New AutoResetEvent(False), .Parameter = "Parameter1"}
            ThreadPool.QueueUserWorkItem(Sub() Call GetWert1(parameter1))
            Dim parameter2 = New Parameter() With {.Done = New AutoResetEvent(False), .Parameter = "Parameter2"}
            ThreadPool.QueueUserWorkItem(Sub() Call GetWert2(parameter2))
    
            parameter1.Done.WaitOne()
            parameter2.Done.WaitOne()
            Return parameter1.Result + parameter2.Result
        End Function
    
        ' Für kombinierte Wertü / Ergebnis Übergabe
        Private Class Parameter
            Friend Done As AutoResetEvent
            Friend Parameter As String
            Friend Result As Double
        End Class
    
        Private Sub GetWert1(value As Parameter)
            Console.WriteLine("GetWert1 " & value.Parameter)
            Threading.Thread.SpinWait(100000)
            Console.WriteLine("GetWert1 completed")
            value.Result = 41
            value.Done.Set()
        End Sub
    
        Private Sub GetWert2(value As Parameter)
            Console.WriteLine("GetWert2 " & value.Parameter)
            Threading.Thread.SpinWait(50000)
            Console.WriteLine("GetWert2 completed")
            value.Result = 42
            value.Done.Set()
        End Sub
    End Class
    Vom Ablauf kurz skiziiert:

    Verwendet wird der ThreadPool - hier vorzuziehen, da sparsamer als immer wieder neue Threads anzulegen (kostet u. U. mehr als die Rechenzeit).
    Mehr siehe: How to: Use a Thread Pool (C# and Visual Basic)

    Die Parameter Klasse fasst Parameterübergabe, Wertrückgabe und die Synchronisation zusammen. Wobei ich eine eine Klasse für die Parameter / Ergebnisübergabe sowie für die Synchronisation verwendet habe, evtl. brauchst Du unterschiedliche.

    In Parameter werden der String Parameter (ggf. auch weitere) übergeben. Das Ergebnis wird Result zugewiesen.

    Das Done - AutoResetEvent teilt jeweils am Ende mit, dass der GetWertX - Thread fertig ist (vorher ist Result ungültig).

    Die Summe wartetet dann auf beide Thread via WaitOne; via WaitAll könnte das mit einem Aufruf geschehen

    Wie man sieht nimmt die TPL viele Standardaufgaben ab (und optimierter als die eher grobe Übersetzung). Will man mehr mit Threads machen, kann das alleine Grund sein, sich über .NET 4 oder gar 4.5 (VS 2012) Gedanken zu machen.

    Gruß Elmar


    Mittwoch, 13. Februar 2013 22:15
    Beantworter
  • Hallo Christian,

    freut mich, das der Vergleich "überzeugt" hat ;)

    Einen Upgrade-Pfad für Visual Studio 20120 Professional gibt es wohl  nicht mehr, siehe http://www.microsoft.com/visualstudio/eng/buy

    Was Crystal Reports ist mittlerweile in den Händen von SAP und müsste darüber aktualisiert werden.

    Die Alternative auf Microsoft Seite sind die Reporting Services, Bestandteil des SQL Servers. Allerdings gibt es keine Migration von Crystal Report, so dass man nicht einfach wechseln kann, zumindest wenn man größere / komplexere Berichte hat. Mehr siehe:
    Migrating from Business Objects Crystal Reports to SQL Server 2005 Reporting Services (nicht mehr ganz aktuell, da ältere Versionen)

    Gruß Elmar


    Donnerstag, 14. Februar 2013 08:10
    Beantworter

Alle Antworten

  • Hallo Christian,

    im einfachen Falle starte zwei Tasks und Addiere deren Ergebnis:

    Public Class TaskSumResults
        Public Shared Sub Run()
            Dim c As New TaskSumResults()
            Console.WriteLine("Ergebnis: " & c.Summe)
        End Sub
    
        Public Function Summe() As Double
            Dim Wert1 = Task.Factory.StartNew(AddressOf GetWert1)
            Dim Wert2 = Task.Factory.StartNew(AddressOf GetWert2)
    
            Return Wert1.Result + Wert2.Result
        End Function
    
        Private Function GetWert1() As Double
            Threading.Thread.SpinWait(100000)
            Console.WriteLine("GetWert1 completed")
            Return 41
        End Function
    
        Private Function GetWert2() As Double
            Threading.Thread.SpinWait(50000)
            Console.WriteLine("GetWert2 completed")
            Return 42
        End Function
    End Class

    Weiteres siehe Aufgabenparallelität (Task Parallel Library)

    Gruß Elmar

    Mittwoch, 13. Februar 2013 18:28
    Beantworter
  • Hallo Elmar,
    danke für deine Antwort.
    Da ich aber Framework 3.5 (VS2008) verwende, kann ich deinen Code leider nicht verwenden.
    Daher habe ich mit:

                Dim T As New Threading.Thread(AddressOf GetWert1)
                T.Start("para1")
    experimentiert. Leider ist das an der Parameterübergabe gescheitert.

    Da ich in Wirklichkeit auch Parameter an meine Funktionen übergeben muss, habe ich mein Frage-Beispiel ergänzt:

            Public Function Summe() As Double
                Dim Wert1, Wert2 As Double
    
                Wert1 = GetWert1("para1")
                Wert2 = GetWert2("para2")
    
                Return Wert1 + Wert2
            End Function


    Christian Tauschek

    Mittwoch, 13. Februar 2013 20:51
  • Hallo Christian,

    ich hatte gehofft, das käme nicht - eher die Frage nach Async/Await ;)

    Unter .NET 2.0/3.5 muss man mehr tun und das Ganze grob umgeschrieben sähe so aus:

    Public Class ThreadPoolSumResults
        Public Shared Sub Run()
            Dim c As New ThreadPoolSumResults()
            Console.WriteLine("Ergebnis: " & c.Summe)
        End Sub
    
        Public Function Summe() As Double
            Dim parameter1 = New Parameter() With {.Done = New AutoResetEvent(False), .Parameter = "Parameter1"}
            ThreadPool.QueueUserWorkItem(Sub() Call GetWert1(parameter1))
            Dim parameter2 = New Parameter() With {.Done = New AutoResetEvent(False), .Parameter = "Parameter2"}
            ThreadPool.QueueUserWorkItem(Sub() Call GetWert2(parameter2))
    
            parameter1.Done.WaitOne()
            parameter2.Done.WaitOne()
            Return parameter1.Result + parameter2.Result
        End Function
    
        ' Für kombinierte Wertü / Ergebnis Übergabe
        Private Class Parameter
            Friend Done As AutoResetEvent
            Friend Parameter As String
            Friend Result As Double
        End Class
    
        Private Sub GetWert1(value As Parameter)
            Console.WriteLine("GetWert1 " & value.Parameter)
            Threading.Thread.SpinWait(100000)
            Console.WriteLine("GetWert1 completed")
            value.Result = 41
            value.Done.Set()
        End Sub
    
        Private Sub GetWert2(value As Parameter)
            Console.WriteLine("GetWert2 " & value.Parameter)
            Threading.Thread.SpinWait(50000)
            Console.WriteLine("GetWert2 completed")
            value.Result = 42
            value.Done.Set()
        End Sub
    End Class
    Vom Ablauf kurz skiziiert:

    Verwendet wird der ThreadPool - hier vorzuziehen, da sparsamer als immer wieder neue Threads anzulegen (kostet u. U. mehr als die Rechenzeit).
    Mehr siehe: How to: Use a Thread Pool (C# and Visual Basic)

    Die Parameter Klasse fasst Parameterübergabe, Wertrückgabe und die Synchronisation zusammen. Wobei ich eine eine Klasse für die Parameter / Ergebnisübergabe sowie für die Synchronisation verwendet habe, evtl. brauchst Du unterschiedliche.

    In Parameter werden der String Parameter (ggf. auch weitere) übergeben. Das Ergebnis wird Result zugewiesen.

    Das Done - AutoResetEvent teilt jeweils am Ende mit, dass der GetWertX - Thread fertig ist (vorher ist Result ungültig).

    Die Summe wartetet dann auf beide Thread via WaitOne; via WaitAll könnte das mit einem Aufruf geschehen

    Wie man sieht nimmt die TPL viele Standardaufgaben ab (und optimierter als die eher grobe Übersetzung). Will man mehr mit Threads machen, kann das alleine Grund sein, sich über .NET 4 oder gar 4.5 (VS 2012) Gedanken zu machen.

    Gruß Elmar


    Mittwoch, 13. Februar 2013 22:15
    Beantworter
  • Hallo Elmar,
    habe mir zwischenzeitlich die VS2012 Express heruntergeladen und habe deinen Vorschlag getestet und es funktioniert so wie es soll.

    Desweiteren habe ich nun auch schon die 'Parallel.For' - Geschichte eingebaut, sodass ich mich nicht mehr um die Anzahl der Threads kümmern muss. Ist ein super Ding.

    Dazumals habe ich mir die VS2008 professional gekauft. In welcher Preisklasse liegt man denn ungefähr mit einem Update auf VS2012 professional?
    Und was ist die Alternative zu Crystal Reports - wie bei VS2008?

    mfg
    Christian Tauschek


    Christian Tauschek

    Donnerstag, 14. Februar 2013 00:07
  • Hallo Christian,

    freut mich, das der Vergleich "überzeugt" hat ;)

    Einen Upgrade-Pfad für Visual Studio 20120 Professional gibt es wohl  nicht mehr, siehe http://www.microsoft.com/visualstudio/eng/buy

    Was Crystal Reports ist mittlerweile in den Händen von SAP und müsste darüber aktualisiert werden.

    Die Alternative auf Microsoft Seite sind die Reporting Services, Bestandteil des SQL Servers. Allerdings gibt es keine Migration von Crystal Report, so dass man nicht einfach wechseln kann, zumindest wenn man größere / komplexere Berichte hat. Mehr siehe:
    Migrating from Business Objects Crystal Reports to SQL Server 2005 Reporting Services (nicht mehr ganz aktuell, da ältere Versionen)

    Gruß Elmar


    Donnerstag, 14. Februar 2013 08:10
    Beantworter