Für diverse kleine Projekte und Anwendungen in VB.NET verarbeite ich Listen von Aufgaben und Jobs. Meistens lässt man diese logischerweise hintereinander ablaufen. Bei größeren Listen und und intensiveren Rechenoperationen wünscht man sich allerdings eine parallele Abarbeitung in Threads, so dass die Aktionen schneller fertig sind.
Da es mir mit der Zeit zu aufwendig geworden ist die Threadprogammierung in jede Anwendung neu zu entwickeln, habe ich eine Klasse entwickelt, die man in seine eigene Klasse einbinden kann. Voraussetzung ist dass die abzuarbeiten Aktionen ein einer Arraylist vorliegen und die einzelnen Elemente über einen Funktionsaufruf abgearbeitet werden.
Beispiel
Beispiel: Kommt noch...
Funtionen und Properties
- CurrentPostion: Das aktuell bearbeitende Element
- ItemsCount: zeigt die Gesamtanzahl, der zu verarbeiteten Elemente an
- WaitForExit: Loop, die solange läuft bis alle Elemente abgearbeitet wurden
- HasExited: gibt true zurück, wenn alle Elemente abgearbeitet wurden
- Start: startet alle Threads, wartet nicht auf die Beendigung der Threads. Um zu Überprüfen, ob alle Elemente durchlaufen wurden
WaitForExitoderHasExitednutzen
VCS File:
/trunk/ThreadWorker/ThreadWorker.vb
SVN Browser: vbnettools -> /trunk/ThreadWorker/ThreadWorker.vb
'$Id: ThreadWorker.vb 18 2010-03-24 13:29:02Z espendiller $
'$HeadURL: file:///var/svn-repos/vbnettools/trunk/ThreadWorker/ThreadWorker.vb $
''' <summary>
''' Simple template for Threads usage
''' </summary>
''' <remarks></remarks>
Public MustInherit Class ThreadWorker
Private _CurrentPosition As Double = 0
Private _MaxThreads As Integer = 4
Private _ThreadsArray As New List(Of Threading.Thread)
Private _Items As New ArrayList
Private _ItemsCount As Integer
Public Event Finished()
Public Event PercentDone(ByVal Percent As Double)
Public Event ItemFinished(ByVal CurrentPosition As Integer, ByVal Thread As Integer, ByVal ReturnString As String)
#Region "Properties"
''' <summary>
''' How many Threads do we want? Default = 4
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Property MaxThreads() As Integer
Get
Return _MaxThreads
End Get
Set(ByVal value As Integer)
_MaxThreads = value
End Set
End Property
''' <summary>
''' A list with Object to work on
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Property Items() As ArrayList
Get
Return _Items
End Get
Set(ByVal value As ArrayList)
_Items = value
_ItemsCount = _Items.Count
End Set
End Property
''' <summary>
''' Get the last finished item as integer
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
ReadOnly Property CurrentPostion() As Integer
Get
Return _CurrentPosition
End Get
End Property
''' <summary>
''' Get overall items count
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
ReadOnly Property ItemsCount() As Integer
Get
Return _ItemsCount
End Get
End Property
#End Region
Sub Start()
Call StartBefore()
'add wanted threads to array for later usage
For i As Integer = 0 To _MaxThreads - 1
_ThreadsArray.Add(New Threading.Thread(AddressOf WorkerThread))
Next
'walk through array of threads and start each one
For i As Integer = 0 To _ThreadsArray.Count - 1
Dim myThread As Threading.Thread = _ThreadsArray.Item(i)
myThread.Start(i)
System.Threading.Thread.Sleep(10)
Next
'a simple thread the will raise the Finished() event if all done
Dim FishinedThread As New Threading.Thread(AddressOf WaitForExitThreadEvent)
FishinedThread.Start()
End Sub
''' <summary>
''' return true if all threads are finished
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Function HasExited() As Boolean
Dim back As Boolean = True
For Each myThread As Threading.Thread In _ThreadsArray
If myThread.IsAlive = True Then
Return False
End If
Next
Return back
End Function
''' <summary>
''' wait for all threads to be finished in parent thread
''' </summary>
''' <remarks></remarks>
Sub WaitForExit()
Do While Me.HasExited = False
System.Threading.Thread.Sleep(500)
Loop
End Sub
''' <summary>
''' Helper for WaitForExit()
''' </summary>
''' <remarks></remarks>
Private Sub WaitForExitThreadEvent()
Call WaitForExit()
RaiseEvent Finished()
End Sub
''' <summary>
''' Sub started by threads and walk through array list
''' </summary>
''' <param name="Thread"></param>
''' <remarks></remarks>
Private Sub WorkerThread(ByVal Thread As Integer)
Do While _CurrentPosition < _ItemsCount
'how much is done all ready in percent
RaiseEvent PercentDone(Math.Round(_CurrentPosition / _ItemsCount * 100, 1))
'for thread safety: before do something with this variable set new value
_CurrentPosition += 1
'do the funny stuff
Dim BackStr As String = WorkItem(_CurrentPosition - 1, Thread)
'Calls WorkItem return text and raise the event
RaiseEvent ItemFinished(_CurrentPosition - 1, Thread, BackStr)
Loop
End Sub
''' <summary>
''' This function does working stuff; you must override it
''' </summary>
''' <param name="CurrentPosition">The Current Item as Integer</param>
''' <param name="Thread">The Thread which did the work</param>
''' <returns>a return string value that can use in ItemFinished</returns>
''' <remarks></remarks>
MustOverride Function WorkItem(ByVal CurrentPosition As Integer, ByVal Thread As Integer) As String
''' <summary>
''' Optional: Function that is perfomed before we Start() our threads
''' </summary>
''' <remarks></remarks>
Overridable Sub StartBefore()
'nothing to do
End Sub
End Class