ManualResetEvent vs ManualResetEventSlim

manualreseteventslim

Dal .NET 4 è stato introdotto un nuovo tipo di ManualResetEvent chiamato ManualResetEventSlim che permette di avere delle performance migliori qualora il tempo di blocco atteso sia molto breve.

Questo miglioramento viene effettuato effettuando dello spinning per un determinato numero di operazioni prima di effettuare il context switch e passare al blocking.

Permette, inoltre, di cancellare un Wait utilizzando un CancellationToken, cosa impossibile con i classici ManualResetEvent.

La classe permette o a costruttore o mediante la property SpinCount di impostare il numero di spin da effettuare prima di effettuare un vero block.

Utilizzo

L’utilizzo di un ManualResetEventSlim è estremamente simile al suo simile ManualResetEvent, le differenze sono le seguenti:

  • Il metodo WaitOne() dei ManualResetEvent è stato rinominato in Wait() che ha in ingresso, oltre ad un timeout in ms, anche un TimeSpan o un CancellationToken
  • Presenta una property get-only IsSet che permette di sapere se è stato o meno settato (di fatto analoga a WaitOne(0))

Chi preferire?

Dal libro C# 9.0 in a Nutshell leggo che ManualResetEventSlim può essere fino a 50 volte più veloce in scenari dove l’attesa è minima in quanto non vi è alcun passaggio al sistema operativo.

Per capire quanto deve essere minima questa attesa ho creato il seguente benchmark:

[ShortRunJob]
public class ManualResetEventTest
{
    [Params(0, 1, 10)]
    public int MillisecondsSleep;

    [Benchmark]
    public void ManualResetEventSlim()
    {
        using var mres = new ManualResetEventSlim(false);
        var t = Task.Run(() =>
        {
            mres.Wait();
        });

        Thread.Sleep(MillisecondsSleep);
        mres.Set();
        t.Wait();
    }
    
    [Benchmark]
    public void ManualResetEvent()
    {
        using var mres = new ManualResetEvent(false);
        var t = Task.Run(() =>
        {
            mres.WaitOne();
        });

        Thread.Sleep(MillisecondsSleep);
        mres.Set();
        t.Wait();
    }
}

Che porta ai seguenti risultati:

Come si può notare quando il tempo di attesa è maggiore o uguale a 1ms i due metodi si equivalgono. La differenza sostanziale si ha quando ho un tempo di sleep di 0ms (quindi un solo context switch senza ulteriori attese) dove ho un miglioramento di performance di 6x.

Per rimuovere l’overhead della creazione dei task ho pensato a questo ulteriore benchmark:

[Benchmark]
public void ManualResetEventSlimSetWait()
{
    using var mres = new ManualResetEventSlim(false);
    mres.Set();
    mres.Wait();
}

[Benchmark]
public void ManualResetEventSetWait()
{
    using var mres = new ManualResetEvent(false);
    mres.Set();
    mres.WaitOne();
}

In questo esempio al momento del wait il ManualResetEvent è già stato impostato a true, di fatto non ho quindi alcuna attesa.

I risultati sono i seguenti:

Il ManualResetEventSlim , qualora il semaforo sia già stato settato, è decisamente più veloce; stiamo parlando di circa 2 ordini di grandezza.

Conclusioni

Nella stragrande maggioranza dei casi utilizzare un ManualResetEvent è più che sufficiente, la differenza di performance è trascurabile.

Ha senso utilizzare il ManualResetEventSlim in caso eventi dove spesso l’attesa è nulla (è già stato effettuato un Set()) oppure inferiore a 1ms.

Indice

Share
Ultimi articoli
Join

Newsletter

Nessuno spam, solo articoli interessanti ;)

Focus

Post correlati

semaphoreslim

SmaphoreSlim 101

SemaphoreSlim è una classe che permette la sincronizzazione di n thread che hanno una risorsa (scarsa) condivisa limitandone l’uso ad un numero massimo.

interlocked

Interlocked 101

La sincronizzazione dei thread è un elemento fondamentale nella programmazione asincrona, ne ho infatti parlato in vari post. La soluzione più versatile è sicuramente utilizzare

event

Come testare gli eventi

Testare che degli eventi siano stato effettivamente lanciati in C# non è immediato. Tipicamente è possibile testare che un evento venga lanciato aspettando un ManualResetEvent

Codice Pragmatico

Contatti

Per informazioni, dubbi o consulenze non esitate a contattarmi.

Lascia un messaggio

Ricevi le ultime news

Iscrivi alla newsletter

Solo articoli interessanti, promesso ;)