Alessandro Del Sole's Blog

{ A programming space about Microsoft® .NET® }
posts - 1908, comments - 2047, trackbacks - 352

My Links

News

Your host

This is me! Questo spazio è dedicato a Microsoft® .NET®, di cui sono molto appassionato :-)

Cookie e Privacy

Disabilita cookie ShinyStat

Microsoft MVP

My MVP Profile

Microsoft Certified Professional

Microsoft Specialist

Xamarin Certified Mobile Developer

Il mio libro su VB 2015!

Pre-ordina il mio libro su VB 2015 Pre-ordina il mio libro "Visual Basic 2015 Unleashed". Clicca sulla copertina per informazioni!

Il mio libro su WPF 4.5.1!

Clicca sulla copertina per informazioni! E' uscito il mio libro "Programmare con WPF 4.5.1". Clicca sulla copertina per informazioni!

These postings are provided 'AS IS' for entertainment purposes only with absolutely no warranty expressed or implied and confer no rights.
If you're not an Italian user, please visit my English blog

Le vostre visite

I'm a VB!

Guarda la mia intervista a Seattle

Follow me on Twitter!

Altri spazi

GitHub
I miei progetti open-source su GitHub

Article Categories

Archives

Post Categories

Image Galleries

Privacy Policy

Cicli Parallel.ForEach con Visual Basic

Nell'ultimo post abbiamo introdotto i cicli Parallel.For con Visual Basic e abbiamo visto come questi consentano di scalare l'esecuzione dell'elaborazione dei dati su tutti i processori dell'architettura multi-core della nostra macchina, aprendo thread simultanei per nostro conto senza che noi lo dovessimo fare a manina. Abbiamo anche visto come l'utilizzo del ciclo For parallelo aumenti le performance in modo esponenziale, sempre tenuto conto di un ipotetico lavoro intensivo. Per qualche dettaglio in più sul discorso Parallel Task Library vi rimando al precedente post, mentre in questo riprendo il discorso dei cicli introducendo il ciclo For Each che è fattibile utilizzando il metodo statico Parallel.ForEach. Supponiamo di avere sempre un metodo che simula un lavoro intensivo:

    'Simula un lavoro intensivo

    Sub SimulateProcessing()

        Thread.SpinWait(80000000)

    End Sub

Supponiamo, poi, di avere un altro metodo che restituisce l'ID del thread corrente e che ci occorrerà in seguito per dimostrare l'intervento di Parallel FX:

    Function GetThreadId() As String

        Return " Thread ID = " + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString

    End Function

Infine, ipotizziamo di voler ciclare, nel modo classico, l'elenco dei file della cartella Immagini e di eseguire su di essi un lavoro intensivo:

    Private Sub SomeMethod2()

 

        Dim allFiles = IO.Directory.GetFiles("C:\users\alessandro\pictures").ToList

 

        For Each f In allFiles

            Console.WriteLine(f + GetThreadId())

            SimulateProcessing()

        Next

 

    End Sub

Questo metodo viene richiamato nella Sub Main che sfrutta, tra l'altro, un contatore di tipo StopWatch:

    Sub Main()

 

        Dim sw As Stopwatch = Stopwatch.StartNew

        SomeMethod2()

 

        sw.Stop()

 

        Console.WriteLine("Tempo trascorso: " + sw.ElapsedMilliseconds.ToString) 

        Console.ReadLine()

    End Sub

Se avviamo l'applicazione, noteremo che, come di consueto, le risorse di sistema non vengono poi sfruttate molto:

Al termine dell'operazione, il risultato sarà simile al seguente: 

Circa 25 secondi, quindi. Ora riscriviamo il ciclo in questo modo:

    Private Sub SomeMethod2()

 

        Dim allFiles = IO.Directory.GetFiles("C:\users\alessandro\pictures").ToList

 

        Parallel.ForEach(Of String)(allFiles, Sub(f)

                                                  Console.WriteLine(f + GetThreadId())

                                                  SimulateProcessing()

                                               End Sub)

    End Sub

Possiamo notare come il primo argomento del metodo Parallel.ForEach sia la collezione da ciclare e che il secondo argomento è un delegate (in questo caso creato al volo tramite statement lambda) che mostra un semplice messaggio e invoca la simulazione di lavoro intensivo. Molto semplice e intuitivo. In Visual Basic 2010 è quindi possibile utilizzare le statement lambda, mentre in Visual Basic 2008 dobbiamo necessariamente creare un delegate e richiamarlo tramite AddressOf. Se avviamo ora l'applicazione, l'utilizzo delle risorse di sistema è massimo:

E al termine il risultato è il seguente:

Quasi 16 secondi, circa 9 secondi in meno rispetto al For Each classico. Anche in questo caso dobbiamo notare come, nel modo classico, il tutto vada a gravare su un unico thread, mentre nel caso "parallelizzato" .NET Framework ha aperto più thread contemporaneamente, sui quali viene scalato il lavoro. Il metodo Parallel.ForEach espone altri overload, dei quali ci sarà modo di parlare in altre occasioni. Per il momento, questo post può servire come spunto alla curiosità verso questo nuovo framework.

Anche in questo caso vale la pena di ricordare che i cicli paralleli, così come Parallel LINQ, offrono il massimo risultato su elaborazioni intensive, mentre su operazioni di scarsa entità potrebbero non apportare alcun beneficio.

Alessandro

Print | posted on giovedì 9 luglio 2009 21:57 | Filed Under [ Visual Basic Visual Studio 2010 Parallel Programming ]

Powered by:
Powered By Subtext Powered By ASP.NET