2009-02-17 6 views
6

Su una macchina quad-core, sto considerando la parallelizzazione dell'algoritmo C# /. NET che implica l'avere simultaneamente più thread che leggono la piccola int [] array. Fino ad ora sembra funzionare piuttosto bene, ma non sono sicuro di dove sia specificato che le letture simultanee su un array siano thread-safe in .NET. Qualche indicazione?Accesso simultaneo in lettura su un array int []: è sicuro? È veloce?

Quindi, mi chiedo anche se questo approccio è davvero efficiente? Ci sono situazioni in cui è meglio duplicare effettivamente i dati di input per ogni thread, in modo che non ci sia alcuna lettura simultanea e ogni array (forse?) Abbia l'opportunità di essere memorizzato nella cache vicino alla CPU di affinità?

Qualche idea sulle migliori pratiche relative alle CPU multicore?

risposta

9

Nel tuo caso, le letture simultanee sul tuo array saranno thread-safe.

Per quanto riguarda l'efficacia degli algoritmi, a seconda della dimensione dell'array, se si adatterà alla cache, potrebbero verificarsi miglioramenti delle prestazioni, poiché i multicores "combattono" efficacemente per la cache nella CPU. Se stanno combattendo per riempire la cache con le stesse informazioni, condivideranno il significato di più riscontri cache e prestazioni migliori.

Supponendo che l'array si inserisce nella cache ...

18

Non penso ci sia un problema con letture concorrenti. Potrebbe essere problematico se ci sono contemporaneamente scritture.

I dati immutabili sono intrinsecamente thread-safe.

+0

Sono pienamente d'accordo con te sul fatto che i dati immutabili sono thread-safe. A volte, tuttavia, è difficile determinare se i dati non cambieranno. Ad esempio, un'operazione di lettura apparente (o diciamo 'metodo query') su un oggetto può causare una scrittura internamente. Devi sempre essere alla ricerca di questo. Tuttavia con gli array: la lettura dell'array non la cambierà sicuramente. – Steven

+1

@Steven concorda sul fatto che non si può sempre dire se qualcosa è immutabile. Ma penso che il tuo esempio sia semplicemente un cattivo design. Credo che i dati immutabili (specialmente se condivisi) dovrebbero essere esplicitamente progettati come tali. –

+0

@Marthinho: Non hai idea di quanto cattivo design ho visto nella mia carriera :-) Mi ha reso uno sviluppatore compulsivo e sospettoso. Non mi fido di nessuno, nemmeno di me stesso :-) Tuttavia, sono d'accordo con tutto ciò che hai detto qui. – Steven

4

Non vi è alcun motivo per non leggere il contenuto di un array in concomitanza assumendo che il contenuto non cambierà mai. Non vi è alcun problema di concorrenza, quindi non è necessario copiare.

Dubito che ci sia ancora molto da fare per renderlo più veloce.

3

Non dovrebbe infastidirti. La lettura simultanea non è un problema. Qualsiasi numero di thread può leggere la stessa memoria allo stesso tempo.

2

La sicurezza del thread è solo un problema quando si aggiornano i dati. Se si dispone di più thread simultanei con aggiornamento, l'array dovrà avvolgere gli aggiornamenti (e legge se gli aggiornamenti non sono atomici) in un meccanismo di sincronizzazione. Per una struttura di dati di sola lettura, la concorrenza è un non-problema.

+0

Non necessariamente. In un array, no, non è un problema, ma nelle raccolte, le letture potrebbero non essere del tutto sicure. – Spence

1

L'operatore di assegnazione non è thread-safe.

Ciò significa che se i thread stanno solo leggendo l'array, se l'array è stato inizializzato all'avvio del programma e non cambia, allora si è sicuri.

Tuttavia, se esiste uno scrittore che scrive nuovi valori, si è vulnerabili a una condizione di competizione.

Il problema di base è questo; un lettore inizia a leggere un numero intero. Il valore viene caricato dalla memoria in un registro. A questo punto, il lettore si sposta. Lo scrittore quindi aggiorna il valore in memoria. Il lettore quindi torna indietro e agisce sul valore che ha caricato, che non è più corretto.

Ciò significa che cose come if() non funzionano in modo affidabile. Ad esempio,

if(int_array[5] == 10) 
{ 
} 

può scatenare quando il valore in memoria di int_array[5] non più 10.

Credo in C# è, si dovrebbe avere accesso alle chiamate di funzione Interlocked*(), come ad esempio InterlockedCompareAndSwap(). Questi ti permetteranno di ottenere facilmente la sicurezza del filo in questo caso.