Descrizione :
Semplice esempio pratico di processo che sfrutta il Multithreading in Applicazione Windows Forms.
+ Articolo :
Premessa : il Threading non deve essere inteso come "una pezza" da mettere ad un algoritmo mediocre per "farlo andare più veloce".
L'ottimizzazione in fase di analisi, a monte del codice, è comunque insostituibile.
Qui di seguito faccio un esempio base, un po' "inventato", semplice ma non banale ( io per primo detesto i "tutorial" che "scoprono l'acqua calda" ).
Poniamo di avere una semplice FormMain, Oggetto di avvio dell'Applicazione.
Le Operazioni da eseguire sono 2 :
'Operazione1 'Trova tutti i numeri tra min e max che contengono tutte le cifre "1234567" 'I numeri trovati vengono inseriti in una List.
'Operazione2 'Trova tutti i numeri tra min e max che contengono tutte le cifre "4567890" 'I numeri trovati vengono inseriti in una List.
Salta subito all'occhio che le 2 Operazioni viaggiano su due insiemi numerici diversi.
Come prima, rozza "ottimizzazione" min1 è inutile che sia inferiore a 1234567, come min2 è inutile che sia inferiore a 4056789.
A meno di non voler considerare anche i negativi, non troverei corrispondenze.
TEST 1.
In un'ottica tipicamente "Form" potrei risolverla semplicemente così :
--> Dichiarazioni Form :
Public Class FormMain Private ts As TimeSpan Private startDate As DateTime Private risultatoOp1 As New List(Of Long) Private risultatoOp2 As New List(Of Long) ... ...
--> Test 1 :
Private Sub cmd_test1_Click(sender As System.Object, e As System.EventArgs) Handles cmd_test1.Click startDate = DateTime.Now 'Operazione1 'Trova tutti i numeri tra min e max che contengono tutte le cifre "1234567" 'I numeri trovati vengono inseriti in una List. risultatoOp1.Clear() Dim s1 As String = "1234567" Dim test1 As Boolean Dim min1 As Long = 1234567 Dim max1 As Long = 7654321 For i As Long = min1 To max1 test1 = True For j As Integer = 0 To s1.Length - 1 If Not i.ToString.Contains(s1(j)) Then test1 = False Exit For End If Next If test1 = True Then risultatoOp1.Add(i) Next 'Operazione2 'Trova tutti i numeri tra min e max che contengono tutte le cifre "4567890" 'I numeri trovati vengono inseriti in una List. risultatoOp2.Clear() Dim s2 As String = "4567890" Dim test2 As Boolean Dim min2 As Long = 4056789 Dim max2 As Long = 9876540 For i As Long = min2 To max2 test2 = True For j As Integer = 0 To s2.Length - 1 If Not i.ToString.Contains(s2(j)) Then test2 = False Exit For End If Next If test2 = True Then risultatoOp2.Add(i) Next ts = DateTime.Now - startDate MessageBox.Show("Operazione completata in : " & ts.TotalSeconds.ToString("#.0") & " sec.") End Sub
--> Conclusioni Test 1 :
--> Il thread è unico : lo stesso Main Thread dell'applicazione.
--> FormMain e relativi controlli non si possono usare durante il processo.
--> Tempo Operazione : circa 13 sec. ( sul PC "X" ).
TEST 2.
Cambio strada : adesso voglio che la UI sia libera durante il processo, e inoltre voglio eseguire Op1 e Op2 su due thread separati che riportano a FormMain i risultati.
Tengo la spiegazione all'osso, e preferisco ( come sempre ) postare codice funzionante.
Lascio al lettore l'onere di farsi una cultura su Delegates, Invoke, Threads, Classi, Puntatori, AddressOf, ByRef, ecc...
--> Dichiarazioni Form :
Public Class FormMain Private ts As TimeSpan Private startDate As DateTime Private risultatoOp1 As New List(Of Long) Private risultatoOp2 As New List(Of Long) Private checkRisOps(1) As Boolean Delegate Sub DelRisOp1(ByVal rOp As List(Of Long)) Public delegateRisultatoOp1 As New DelRisOp1(AddressOf SetRisultatoOp1) Private Sub SetRisultatoOp1(ByVal rOp As List(Of Long)) risultatoOp1 = rOp checkRisOps(0) = True CheckRisultati() End Sub Delegate Sub DelRisOp2(ByVal rOp As List(Of Long)) Public delegateRisultatoOp2 As New DelRisOp1(AddressOf SetRisultatoOp2) Private Sub SetRisultatoOp2(ByVal rOp As List(Of Long)) risultatoOp2 = rOp checkRisOps(1) = True CheckRisultati() End Sub Private Sub CheckRisultati() If Not checkRisOps.Contains(False) Then ts = DateTime.Now - startDate MessageBox.Show("Operazione completata in : " & ts.TotalSeconds.ToString("#.0") & " sec.") End If End Sub ... ...
--> Operazioni :
Questa volta non ho più un processo continuo "dietro il Button", ma inserisco le Operazioni in una Classe :
Public Class Operazioni Private m_min As Long Private m_max As Long Private m_caller As FormMain Public Sub New(ByRef caller As FormMain, ByVal min As Long, ByVal max As Long) m_caller = caller m_min = min m_max = max End Sub Public Sub Operazione1() 'Operazione1 'Trova tutti i numeri tra min e max che contengono tutte le cifre "1234567" 'I numeri trovati vengono inseriti in una List. Dim s As String = "1234567" Dim test As Boolean Dim lstOp1 As New List(Of Long) For i As Long = m_min To m_max test = True For j As Integer = 0 To s.Length - 1 If Not i.ToString.Contains(s(j)) Then test = False Exit For End If Next If test = True Then lstOp1.Add(i) Next 'Passaggio del Risultato Operazione1 al Thread Chiamante m_caller.Invoke(m_caller.delegateRisultatoOp1, lstOp1) End Sub Public Sub Operazione2() 'Operazione2 'Trova tutti i numeri tra min e max che contengono tutte le cifre "4567890" 'I numeri trovati vengono inseriti in una List. Dim s As String = "4567890" Dim test As Boolean Dim lstOp2 As New List(Of Long) For i As Long = m_min To m_max test = True For j As Integer = 0 To s.Length - 1 If Not i.ToString.Contains(s(j)) Then test = False Exit For End If Next If test = True Then lstOp2.Add(i) Next 'Passaggio del Risultato Operazione1 al Thread Chiamante m_caller.Invoke(m_caller.delegateRisultatoOp2, lstOp2) End Sub End Class
--> Test 2 :
Private Sub cmd_test2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmd_test2.Click startDate = DateTime.Now 'Operazione1 risultatoOp1.Clear() checkRisOps(0) = False Dim min1 As Long = 1234567 Dim max1 As Long = 7654321 Dim TOp1 As New Threading.Thread(AddressOf New Operazioni(Me, min1, max1).Operazione1) TOp1.IsBackground = True TOp1.Start() 'Operazione2 risultatoOp2.Clear() checkRisOps(1) = False Dim min2 As Long = 4056789 Dim max2 As Long = 9876540 Dim TOp2 As New Threading.Thread(AddressOf New Operazioni(Me, min2, max2).Operazione2) TOp2.IsBackground = True TOp2.Start() End Sub
--> Conclusioni Test 2 :
--> 3 Threads in gioco : il Main Thread dell'applicazione + 2 Threads esterni.
--> FormMain e relativi controlli si possono continuare ad usare durante il processo.
--> Tempo Operazione : circa 7 sec. ( sempre sul PC "X" ).
--> Direi che ne è valsa decisamente la pena...
+ Fine Articolo.
0 commenti:
Posta un commento