2010-03-17 15 views
5

I recently asked su programmi funzionali senza effetti collaterali, e ho imparato cosa significa questo per rendere banali i compiti parallelizzati. Nello specifico, le funzioni "pure" rendono questo banale in quanto non hanno effetti collaterali.Le espressioni lambda/delegate in C# "puro" o possono essere?

Ho anche recentemente esaminato le espressioni LINQ e lambda poiché ho analizzato più volte gli esempi qui su StackOverflow che includono l'enumerazione. Questo mi ha fatto chiedersi se parallelizzare un'enumerazione o un ciclo possa essere "più semplice" in C# ora.

Le espressioni lambda sono "pure" sufficienti per eseguire il parallelismo banale? Forse dipende da cosa stai facendo con l'espressione, ma possono essere abbastanza puri? Sarebbe qualcosa di simile sia teoricamente possibile/banale in C# ?:

  • rompere il ciclo in pezzi
  • eseguire un thread per ciclo attraverso ogni blocco
  • Eseguire una funzione che fa qualcosa con il valore dalla corrente loop di posizione di ciascun thread

ad esempio, dire che ho avuto un sacco di oggetti in un ciclo di gioco (come sto sviluppando un gioco e pensavo alla possibilità di più thread) e aveva a che fare qualcosa con ogni di loro ogni fotogramma, sarebbe th e sopra essere banale da tirare fuori? Guardando IEnumerable sembra che tenga traccia della posizione corrente, quindi non sono sicuro di poter usare le normali collezioni generiche per rompere l'enumerazione in "blocchi".

Siamo spiacenti per questa domanda. Ho usato i proiettili sopra invece dello pseudo-codice perché non so nemmeno abbastanza per scrivere pseudo-codice dalla cima della mia testa. La mia conoscenza di .NET è stata puramente semplice business e sono nuovo per delegati e thread, ecc. Voglio principalmente sapere se l'approccio sopra è buono per perseguire, e se i delegati/lambda non devono preoccuparsi di quando arriva alla loro parallelizzazione.

risposta

17

Prima di tutto, si noti che per essere "puro" un metodo non deve avere solo effetti collaterali. Deve anche restituire sempre lo stesso risultato quando vengono forniti gli stessi argomenti. Quindi, ad esempio, il metodo "Math.Sin" è puro. Ti nutri in 12, ti restituisce peccato (12) ed è sempre lo stesso.Un metodo GetCurrentTime() non è puro anche se non ha effetti collaterali; restituisce un valore diverso ogni volta che lo chiami, indipendentemente da quali argomenti passi.

Si noti inoltre che un metodo puro non dovrebbe mai generare un'eccezione; le eccezioni contano come effetti collaterali osservabili per i nostri scopi.

Secondo, sì, se puoi ragionare sulla purezza di un metodo, allora puoi fare cose interessanti per parallelizzarlo automaticamente. Il problema è che quasi nessun metodo è effettivamente puro. Inoltre, supponiamo di avere un metodo puro; poiché un metodo puro è un candidato perfetto per la memoizzazione, e poiché la memoizzazione introduce un effetto collaterale (muta una cache!) è molto interessante prendere quei metodi che dovrebbero essere puri e renderli impuri.

Ciò di cui abbiamo veramente bisogno è un modo per "addomesticare gli effetti collaterali" come dice Joe Duffy. Un modo per disegnare un riquadro attorno a un metodo e dire "questo metodo non è privo di effetti collaterali, ma i suoi effetti collaterali non sono visibili al di fuori di questa casella", e quindi usare che per guidare la parallelizzazione automatica sicura.

Mi piacerebbe trovare un modo per aggiungere questi concetti a linguaggi come C#, ma questa è tutta una questione di open-research-problem totalmente blue-sky qui; nessuna promessa intesa o implicita.

13

Lambda deve essere essere puro. E poi FrameWork offre la paralellizzazione automatica con una semplice aggiunta a una query LINQ (PLINQ) da .AsParallel.

Ma non è automatico o garantito, il programmatore è responsabile di renderli/mantenerli puri.

+0

AsParallel? Di cosa si tratta? C# 4? O è un download separato? – Bob

+1

Sì, mi dispiace. PLINQ fa parte di .NET 4, esiste anche una versione (beta?) Per 3.5 –

+0

+1 La programmazione funzionale conferisce più responsabilità al programmatore. Identificare i blocchi di codice che possono essere eseguiti in parallelo è uno di questi. – Perpetualcoder

3

Se una lambda è pura o no è legata a ciò che sta facendo. Come concetto non è né puro né impuro.

Ad esempio: la seguente espressione lambda è impura poiché legge e scrive una singola variabile nel corpo. Eseguendolo in parallelo crea una condizione di gara.

var i = 0; 
Func<bool> del =() => { 
    if (i == 42) { return true; } 
    else (i++) { return false; } 
}; 

Contrariamente al seguente delegato è puro e non ha condizioni di gara.

Func<bool> del =() => true; 
3

quanto riguarda la parte del ciclo, si potrebbe anche utilizzare il Parallel.For e Parallel.ForEach per l'esempio sugli oggetti in un gioco. Anche questo fa parte di .net 4, ma puoi scaricarlo come download.

2

C'è una lettura di 13 parti che parla del nuovo supporto di parallelismo in .NET 4.0 here. Include discussioni su LINQ e PLINQ e nella Parte 7. È una buona lettura, quindi dai un'occhiata a

Problemi correlati