Domanda

Interlocked.Increment (ref x) è più veloce o più lento di x ++ per interi e long su varie piattaforme?

È stato utile?

Soluzione

È più lento poiché forza l'azione atomica e agisce come una barriera di memoria, eliminando la capacità del processore di riordinare gli accessi alla memoria attorno all'istruzione.

Dovresti usare Interlocked.Increment quando vuoi che l'azione sia atomica sullo stato che può essere condivisa tra thread - non è inteso per essere una sostituzione completa per x ++.

Altri suggerimenti

Nella nostra esperienza, InterlockedIncrement () e altri su Windows hanno un impatto piuttosto significativo. In un caso di esempio siamo stati in grado di eliminare l'interblocco e utilizzare invece ++ / -. Questo da solo ha ridotto il tempo di esecuzione da 140 secondi a 110 secondi. La mia analisi è che l'interblocco forza un roundtrip di memoria (altrimenti come potrebbero vederlo altri core?). Una lettura / scrittura della cache L1 è di circa 10 cicli di clock, ma una memoria di lettura / scrittura più simile a 100.

In questo caso di esempio, ho stimato il numero di operazioni di incremento / decremento a circa 1 miliardo. Quindi su una CPU da 2 Ghz sono circa 5 secondi per ++ / - e 50 secondi per l'interblocco. Distribuisci la differenza tra più thread ed è vicino a 30 secondi.

Pensaci per un momento e ti renderai conto che una chiamata Increment non può essere più veloce di una semplice applicazione dell'operatore di incremento. Se lo fosse, l'implementazione del compilatore dell'operatore di incremento chiamerebbe Increment internamente e farebbe lo stesso.

Ma, come puoi vedere testandolo tu stesso, non si comportano allo stesso modo.

Le due opzioni hanno scopi diversi. Utilizzare l'operatore di incremento in generale. Usa Increment quando hai bisogno che l'operazione sia atomica e sei sicuro che anche tutti gli altri utenti di quella variabile stanno usando operazioni interbloccate. (Se non collaborano tutti, non aiuta davvero.)

È più lento. Tuttavia, è il modo generale più performante che io conosca per ottenere la sicurezza del thread su variabili scalari.

Sarà sempre più lento perché deve eseguire un blocco del bus CPU rispetto al semplice aggiornamento di un registro. Tuttavia, le CPU moderne raggiungono prestazioni prossime al registro, quindi è trascurabile anche nell'elaborazione in tempo reale.

Il mio test delle prestazioni:

volatile: 65.174.400

blocco: 62.428.600

interbloccato: 113.248.900

TimeSpan span = TimeSpan.FromSeconds(5);

object syncRoot = new object();
long test = long.MinValue;

Do(span, "volatile", () => {

    long r = Thread.VolatileRead(ref test);

    r++;

    Thread.VolatileWrite(ref test, r);
});

Do(span, "lock", () =>
{
    lock (syncRoot)
    {
        test++;
    }
});

Do(span, "interlocked", () =>
{
    Interlocked.Increment(ref test);
});
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top