2011-12-31 7 views
32

Abbiamo un multitasking ad alte prestazioni, vicino all'applicazione C# in tempo reale. Questa performance è stata ottenuta principalmente implementando il multitasking cooperativo internamente con uno scheduler nazionale. Questo è spesso chiamato micro-thread. In questo sistema tutte le attività comunicano con altre attività tramite le code.C# continuazione di prima classe tramite l'interoperabilità C++ o in un altro modo?

Il problema specifico che abbiamo sembra essere risolvibile solo tramite continuazioni di prima classe che C# non supporta.

In particolare, il problema si pone in 2 casi relativi alle code. Ogni volta che una determinata attività esegue del lavoro prima di posizionare un oggetto su una coda. Cosa succede se la coda è piena?

Al contrario, un'attività diversa può richiedere un po 'di lavoro e quindi è necessario rimuovere un elemento da una coda. Cosa succede se quella coda è vuota?

Abbiamo risolto questo problema nel 90% dei casi collegando le code alle attività per evitare che le attività vengano richiamate se una delle loro code in uscita è piena o la coda in ingresso è vuota.

Inoltre alcune attività sono state convertite in macchine a stati in modo che possano gestire se una coda è piena/vuota e continuare senza attendere.

Il vero problema si pone in alcuni casi limite in cui non è pratico fare una di queste soluzioni. L'idea in questo scenario sarebbe quella di salvare lo stato di stack nel punto e passare a un'attività diversa in modo che possa eseguire il lavoro e successivamente riprovare l'attività di attesa ogni volta che è in grado di continuare.

In passato, abbiamo tentato di richiamare l'attività in attesa nella pianificazione (in modo ricorsivo) per consentire alle altre attività di riprendere in seguito l'attività in attesa. Tuttavia, ciò ha portato a troppe situazioni di "stallo".

C'è stato un esempio da qualche parte di un host CLR personalizzato per fare in modo che i thread .NET funzionino come "fibre" che essenzialmente consente di cambiare lo stato di stack tra i thread. Ma ora non riesco a trovare alcun codice di esempio per questo. Inoltre sembra che ci vorrà una certa complessità per farlo bene.

Qualcuno ha altre idee creative su come passare tra le attività in modo efficiente ed evitare i problemi di cui sopra?

Ci sono altri host CLR che offrono questo, commerciale o altro? C'è qualche libreria nativa aggiuntiva che può offrire qualche forma di continuazione per C#?

+1

Esempio di host CLR in modalità fibra: potresti riferirti alle serie di blog di Dino Viehland su questo argomento, che iniziano qui: http://blogs.msdn.com/b/dinoviehland/archive/2004/08/16/215140. aspx – bobbymcr

+3

Nit: un deadlock non è un problema di efficienza. È un problema di correttezza. (Inoltre, qual è la differenza tra una coda non legata e non più memoria? Stato è stato e deve essere memorizzato da qualche parte.) –

+8

Stiamo aggiungendo una forma di continuazione a C# 5. Anche se non sono esattamente chiamate di prima classe/continuazioni in stile cc, sono moralmente equivalenti. Controlla il "CTP asincrono" per una versione di anteprima di esso. http://msdn.microsoft.com/en-us/vstudio/gg316360.aspx. Vedi anche il recente articolo di MSDN Magazine di Stephen Toub sulle caratteristiche delle prestazioni della funzione asincrona. –

risposta

1

In realtà, abbiamo deciso una direzione per andare con questo. Stiamo usando il pattern Observer con Message Passsing. Abbiamo costruito una libreria nazionale per gestire tutte le comunicazioni tra "agenti" simili a un processo di Erlang. In seguito prenderemo in considerazione l'utilizzo di AppDomains per separare gli agenti ancora meglio l'uno dall'altro. Le idee di progettazione sono state prese in prestito dal linguaggio di programmazione di Erlang che ha un'elaborazione multintegrale e distribuita estremamente affidabile.

+0

Se sei curioso di sapere ciò, puoi trovare altri post che ho inserito su StackOverflow in particolare sulla gestione dello stile di Erlang in C#. Quelli sono stati fatti mentre cercavano aiuto per avvolgere la mia mente sui pro e contro del messaggio di Erlang che passava per sfruttare le idee progettuali lì. Nello specifico, il problema della coda completa è risolto in Erlang e ora lo prende in prestito così come la comunicazione copia per valore. – Wayne

+0

È interessante notare che il motore di trasmissione messaggi che abbiamo creato ora determina se il messaggio che viene ricevuto verrà eseguito sullo stesso thread/core del mittente, quindi elimina completamente i blocchi. Quindi la contesa si verifica solo quando è assolutamente necessario saltare a un altro core che induce semplicemente un errore di cache L1 che è 4 volte più economico su un quad core rispetto a un'operazione CAS poiché CAS arresta tutti i core mentre la cache L1 manca solo sul single core che legge i dati quello è stato scritto – Wayne

+0

Per le continuazioni, utilizziamo semplicemente una macchina a stati poiché è così che i compilatori lo fanno comunque. Purtroppo, non vi è alcun zucchero sintattico in C# per le continuazioni. Ma una macchina statale ha lo scopo benissimo! Fortunatamente ci sono solo una manciata di posti nel sistema in cui sono necessari i continuations/state machine. – Wayne

0

La soluzione al problema consiste nell'utilizzare algoritmi lock-free che consentono l'avanzamento a livello di sistema di almeno un'attività. È necessario utilizzare un assemblatore in linea dipendente dalla CPU per accertarsi che sia CAS atomico (confronta e scambia). Wikipedia ha uno article e modelli descritti lo book di Douglas Schmidt chiamato "Architettura del software orientata al pattern, Pattern per oggetti concatenati e in rete". Non mi è immediatamente chiaro come lo farete sotto il framework dotnet.

Un altro modo per risolvere il problema è utilizzare il modello di sottoscrizione di pubblicazione o possibili pool di thread.

Spero che questo sia stato utile?

+0

Grazie, ma anche il test di CAS è molto lento. Perché ogni CAS sia valido, tutti i core devono essere sincronizzati. La nostra strategia ora utilizza i blocchi ZERO, che include zero spin come il CAS. Invece i diversi componenti comunicano tramite il passaggio di messaggi simile al design di erlang. Ciò consente una vera elaborazione parallela senza errori di cache o rallentamenti CAS. – Wayne

2

C'è la C# 5 CTP, che esegue una trasformazione-passing-style continuazione rispetto ai metodi dichiarati con il nuovo async parola chiave, e le chiamate in base continuazione-passing quando si utilizza la parola chiave await.

Questa non è in realtà una nuova funzionalità CLR, ma piuttosto una serie di direttive per il compilatore per eseguire la trasformazione CPS sul codice e una manciata di routine di libreria per la manipolazione e la pianificazione delle continuazioni. I record di attivazione per i metodi async vengono posizionati nell'heap anziché nello stack, quindi non sono collegati a un thread specifico.

+1

Si potrebbe voler notare che si tratta di una trasformazione CPS estremamente limitata. – leppie

+1

Manca la potenza, le prestazioni e la flessibilità del modello di Osservatore in piena regola con passaggio dei messaggi. Il passaggio dei messaggi sembra essere la soluzione più elegante ed efficiente per la programmazione multinazionale e distribuita. – Wayne

+0

@Wayne Concordato. Ne parlo solo perché è una funzionalità linguistica di prima classe (sebbene non di prima classe a livello di runtime, dal momento che non può essere applicata al codice che non è scritto e compilato per la funzione). –

1

No, non funzionerà. C# (e anche IL) è un linguaggio troppo complesso per eseguire tali trasformazioni (CPS) in modo generale. Il meglio che puoi ottenere è ciò che C# 5 offrirà. Detto questo, probabilmente non sarai in grado di rompere/riprendere con cicli/iterazioni di ordine superiore, il che è veramente quello che vuoi da continuazioni reifiable per scopi generali.

1

modalità Fiber è stato rimosso dalla v2 del CLR a causa di problemi in condizioni di stress, vedi:

Per il mio supporto in fibra di conoscenza non ha ancora l'ape è stata aggiunta nuovamente, anche se dalla lettura degli articoli di cui sopra è possibile aggiungere nuovamente (h Tuttavia, il fatto che nulla sia stato menzionato per 6-7 anni sull'argomento mi fa pensare che sia improbabile).

supporto proposito fibra è stato destinato ad essere un modo per applicazioni che utilizzano fibre (ad esempio SQL Server) per ospitare il CLR in un modo che permette loro di massimizzare le prestazioni esistente, non come un metodo per consentire Applicazioni di rete per creare centinaia di thread - in fibre corte non è una soluzione magica per il tuo problema, tuttavia se hai un'applicazione che utilizza fibre desideri ospitare il CLR, allora le API di hosting gestite forniscono i mezzi per il CLR a " funziona bene "con la tua applicazione. Una buona fonte di informazioni su questo sarebbe il managed hosting API documentation, o per esaminare come SQL Server ospita il CLR, di cui ci sono diversi articoli altamente informativi in ​​giro.

Leggere anche Threads, fibers, stacks and address space.

Problemi correlati