Antonio Esposito's


Prodotti tipici .NETtiani

Multithreading

Ciao a tutti

Voglio postare un esempio di multithreading in cui leggo e comprimo tutti i file di una directory (e sottodirectory).
L'approccio è questo:
1) Leggiamo tutti i nomi dei file e li mettiamo in una coda
2) Creiamo dei thread in cui cicliamo sulla coda fino all'esaurimento
3) In ogni thread mettiamo un Handle con cui segnalare al thread principale la fine dell'esecuzione
4) Alla fine serializziamo il bag che rappresenta il file di output

Vediamo come fare in una applicazione c# console di esempio:

[Serializable] //questa è la classe di scambio
public class DataClass
{
public string FName { get; set; }
public byte[] FData { get; set; }
}

static void Main(string[] args)
{
string inputPath = @"C:\Users\Antonio\Desktop\PRC";

//mi creo una coda FIFO per accedere all'elenco dei nomi dei files in modo threadsafe dai threads che andrò a creare
var fileNames = new Queue<string>(Directory.GetFiles(inputPath, "*.*", SearchOption.AllDirectories));
var locks = new List<AutoResetEvent>(); //la lista di Handle
var data = new List<DataClass>(); //la bag di output
var st = new Stopwatch(); //per testare il tempo
var threadCount = Environment.ProcessorCount * 2; //il numero di thread, in questo caso è variabile in base alla cpu della macchina
st.Start();

Console.WriteLine("Threads: {0}", threadCount);

for (int i = 1; i < threadCount; i++) //itero sul numero di thread che ho deciso di creare
{
    var t = new Thread(delegate(object l) //essendo un metodo anonimo, questo è quello che verrà eseguito all'interno del thread
    {
        while (fileNames.Count>0)
        {
            string fname;

            //scodo un nome di file
            lock (fileNames)
                fname = fileNames.Dequeue();

            //leggo e comprimo il file
            using (var m = new MemoryStream())
            {
                using (var df = new DeflateStream(m, CompressionMode.Compress))
                {
                    var b = File.ReadAllBytes(fname);
                    df.Write(b, 0, b.Length);
                }

                //aggiungo il file compresso nella mia variabile di output
                data.Add(new DataClass() { FName = fname, FData = m.ToArray() });
            }
        }
        (l as AutoResetEvent).Set(); //segnalo che questo thread ha completato il suo lavoro
    });

    //creo un nuovo Handle da usare come flag di fine elaborazione
    var k = new AutoResetEvent(false);
    locks.Add(k);
    t.Start(k);
}
//aspetto che tutti i thread abbiano finito di elaborare
AutoResetEvent.WaitAll(locks.ToArray());

st.Stop();
Console.WriteLine("OK in  {0}s", st.Elapsed.Seconds);
st.Reset();
st.Start();

//scrivo in output il file
using (var w = File.OpenWrite(@"output.dat"))
{
    var b = new BinaryFormatter();
    b.Serialize(w, data);
}

st.Stop();
Console.WriteLine("OK in  {0}s", st.Elapsed.Seconds);

Console.ReadLine();

 

 

Categoria: Tips
sabato, 10 apr 2010 Ore. 18.47
Statistiche
  • Views Home Page: 10.783
  • Views Posts: 59.056
  • Views Gallerie: 0
  • n° Posts: 44
  • n° Commenti: 16
Copyright © 2002-2007 - Blogs 2.0
dotNetHell.it | Home Page Blogs
ASP.NET 2.0 Windows 2003