AntonioGanci

Il blog di Antonio Ganci
posts - 201, comments - 420, trackbacks - 31

Eseguire x operazioni contemporamente utilizzando la classe Semaphore

In questi giorni ho avuto la necessità di eseguire n operazioni in gruppi al max di x operazioni contemporaneamente. In pratica devo estrarre alcune informazioni da pagine web e per ottimizzare le performance eseguo 5 (parametro configurabile) scaricamenti contemporaneamente da altrettanti thread.

Per gestire il tutto ho usato la classe Semaphore, vediamo come.

Partiamo dal main:

    1 using System;

    2 using System.Collections.Generic;

    3 using System.Threading;

    4 

    5 namespace MultithreadingExperiments

    6 {

    7     static class Program

    8     {

    9         [STAThread]

   10         static void Main()

   11         {

   12             Semaphore pool = new Semaphore(5, 5);

   13             Random rand = new Random();

   14             List<Thread> threads = new List<Thread>();

   15             for (int i = 0; i < 100; i++)

   16             {

   17                 ConsoleWriter writer = new ConsoleWriter(i, rand.Next(1, 10) * 1000, pool);

   18                 Thread thread = new Thread(new ThreadStart(writer.DoSomeWork));

   19                 thread.Start();

   20                 threads.Add(thread);

   21             }

   22             foreach (Thread thread in threads)

   23             {

   24                 thread.Join();

   25             }

   26             Console.ReadLine();

   27         }

   28     }

   29 }

Come si vede dal loop for nella riga 15 devono essere eseguite 100 writer.DoSomeWork al max a gruppi di 5 contemporaneamente; a garantirci questo ci pensa la classe Semaphore creata con i valori:

initialCount: The initial number of requests for the semaphore that can be granted concurrently.

maximumCount: The maximum number of requests for the semaphore that can be granted concurrently.

inizializzati a 5.

Vediamo la classe ConsoleWriter:

    1 using System;

    2 using System.Threading;

    3 

    4 namespace MultithreadingExperiments

    5 {

    6     class ConsoleWriter

    7     {

    8         private Semaphore m_pool;

    9         private readonly int m_id;

   10         private int m_sleepingTime;

   11 

   12         public ConsoleWriter(int id, int sleepingTime, Semaphore pool)

   13         {

   14             m_id = id;

   15             m_sleepingTime = sleepingTime;

   16             m_pool = pool;

   17         }

   18 

   19         public void DoSomeWork()

   20         {

   21             m_pool.WaitOne();

   22             Console.WriteLine("Thread {0} started", m_id);

   23             Thread.Sleep(m_sleepingTime);

   24             Console.WriteLine("Thread {0} finished his work", m_id);

   25             m_pool.Release();

   26         }

   27     }

   28 }

Nel metodo DoSomeWork viene chiamato il metodo WaitOne che ritorna quando c'è almeno un risorsa disponibile (noi ne abbiamo specificate al max 5). Quando il metodo termina viene richiamato il metodo Release il quale permette ad un altro thread in attesa di partire.

Nel codice di produzione sarebbe una buona norma inserire il codice del metodo DoSomeWork in un blocco try/finally in modo che sia garantita la chiamata al metodo Release.

Le ultime righe del metodo main attendono che tutti i thread siano terminati.

Print | posted on martedì 19 giugno 2007 15:08 | Filed Under [ Tips ]

Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET