2010-03-22 5 views
9

In Python la parola chiave yield può essere utilizzata in entrambi i contesti push e pull, so come eseguire il contesto pull in C#, ma come raggiungere la spinta. Inserisco il codice che sto cercando di replicare in C# da python:Come si possono fare le routine di co-routine usando C#?

def coroutine(func): 
    def start(*args,**kwargs): 
    cr = func(*args,**kwargs) 
    cr.next() 
    return cr 
    return start 

@coroutine 
def grep(pattern): 
    print "Looking for %s" % pattern 
    try: 
    while True: 
     line = (yield) 
     if pattern in line: 
     print line, 
    except GeneratorExit: 
    print "Going away. Goodbye" 
+0

Eric Lippert ha un post sul blog da qualche parte –

+1

Considerare la formattazione del codice un po 'di più usando tab/spazi. La formattazione delle schede – Mizipzor

+3

... effettivamente è necessaria e non importa di tempo, è questione di Python. –

risposta

13

Se ciò che si desidera è una "collezione osservabile", ovvero una raccolta che spinge i risultati verso di te anziché lasciarli attrarre dal consumatore, è probabile che si desideri esaminare le estensioni di Reactive Framework. Ecco un articolo su di esso:

http://www.infoq.com/news/2009/07/Reactive-Framework-LINQ-Events

Ora, come si nota, è possibile costruire sia "push" e "pull" iteratori stile facilmente se si dispone di coroutine disponibili. (Oppure, come sottolinea Thomas, puoi costruirli anche con continuazioni.) Nella versione attuale di C# non abbiamo coroutine reali (o continuazioni). Tuttavia, siamo molto preoccupati per il dolore che gli utenti provano nei confronti della programmazione asincrona .

L'implementazione di coroutine a base di fibre come funzionalità di linguaggio di prima classe è una tecnica che potrebbe essere utilizzata per semplificare la programmazione asincrona, ma questa è solo una delle possibili idee di molte che stiamo attualmente ricercando.Se si dispone di uno scenario davvero solido, in cui le coroutine svolgono un lavoro migliore di qualsiasi altra cosa - inclusa la struttura reattiva - allora mi piacerebbe saperne di più. Più dati realistici abbiamo su quali siano i problemi reali che le persone affrontano nella programmazione asincrona, più è probabile che presenteremo una buona soluzione. Grazie!

AGGIORNAMENTO: Abbiamo recentemente annunciato che stiamo aggiungendo flussi di controllo asincroni tipo coroutine alla prossima versione di C# e VB. Puoi provare tu stesso con la nostra edizione di Community Technology Preview, che puoi scaricare here.

+0

Uno di questi scenari è la simulazione guidata dagli eventi (stile Simula). Ho un progetto che utilizza le fibre Win32 che non riesco ancora a portare su .NET –

+0

Penso che la programmazione asincrona in C# sia ottima. Mi piace il MailboxProcessor in stile F in Erlang. Per quanto riguarda le co-routines, le trovo molto interessanti. So che sono vecchie tecnologie e sono state spazzate via quando sono stati introdotti i thread, ma mi piace l'idea che io sappia esattamente quando una routine verrà eseguita e quando passerà il controllo indietro. Il problema principale che ho riscontrato con i thread è la mancanza di controllo e la pesantezza generale della loro creazione. Fanno comunque un bel livello di astrazione del pensiero, che richiede pochissimi sforzi per implementare :) – WeNeedAnswers

+0

Grazie Eric. Sembra molto promettente! – WeNeedAnswers

6

C# non ha generali co-routine. Un co-routine generale è dove la co-routine ha il proprio stack, cioè può invocare altri metodi e quei metodi possono "produrre" valori. L'implementazione di co-routines generali richiede la creazione di alcune cose intelligenti con stack, possibilmente fino all'allocazione di stack frame (le strutture nascoste che contengono variabili locali) nello heap. Questo può essere fatto, alcune lingue lo fanno (ad esempio Scheme), ma è alquanto complicato farlo correttamente. Inoltre, molti programmatori trovano la funzione difficile da capire.

Le co-routine generali possono essere emulate con le filettature. Ogni thread ha il suo stack. In una configurazione di co-routine, entrambi i thread (il chiamante iniziale e il thread per la co-routine) alterneranno il controllo, non verranno mai eseguiti simultaneamente. Il meccanismo "yield" è quindi uno scambio tra i due thread e, in quanto tale, è costoso (sincronizzazione, un roundtrip attraverso il kernel del sistema operativo e lo scheduler ...). Inoltre, vi è molto spazio per perdite di memoria (la co-routine deve essere esplicitamente "arrestata", altrimenti il ​​thread in attesa si bloccherà per sempre). Quindi, questo è raramente fatto.

C# fornisce una funzione di co-routine bastardizzata denominata iteratori. Il compilatore C# converte automaticamente il codice iteratore in una specifica classe di stato, con le variabili locali che diventano campi di classe. La resa è quindi, a livello di VM, un semplice return. Una cosa del genere è fattibile fintanto che il "rendimento" viene eseguito dal codice iteratore stesso, non da un metodo invocato dal codice iteratore. Gli iteratori C# coprono già molti casi d'uso e i progettisti C# non erano disposti ad andare più avanti sulla strada fino a continuations. Alcune persone sarcastiche sono ansiose di affermare che implementare continui con funzionalità complete avrebbe impedito a C# di essere efficiente quanto il suo arci-nemico Java (sono possibili fattibili continuazioni, ma ciò richiede un po 'di lavoro con il GC e il compilatore JIT).

+0

bella risposta. Penso di aver trovato quello che stavo cercando di fare con C#, IObservable. Quella roba sulla pila, fa Python sotto le copertine, perché non penso che lo faccia. Usa vaniglia C.Non lo so per certo però. Sto cercando di evitare l'uso di thread, quindi perché ero interessato alla root di routine. Trovo che se ho il pieno controllo della mia programmazione, e ho gli strumenti per evitare i thread, perché non provare. La roba di coroutine dovrebbe funzionare a meraviglia tutto essere racchiusa in una falsa identità IObservable :) – WeNeedAnswers

+0

Java efficiente ... :) scusami mi ha fatto sorridere. Ricordo di aver fatto una soluzione usando JBoss. la cosa non avrebbe rilasciato oggetti, abbiamo detto al nostro cliente finale (T.U.I. Thomas Cook) che avrebbe dovuto accenderlo e spegnerlo di tanto in tanto. :) – WeNeedAnswers

+1

Se non ti piace Java, per quanto riguarda l'efficienza, è probabile che non sarai molto soddisfatto nemmeno di C#. Sono abbastanza simili a questo riguardo. In realtà sono abbastanza simili sotto ogni punto di vista. –

0

Mi piacerebbe vedere un'API basata su fibra per .Net.

Ho tentato di utilizzare l'API della fibra nativa in C# tramite p/invocare un po 'di tempo fa, ma poiché la gestione delle eccezioni del runtime (erroneamente) rende ipotesi basate su thread, le cose si sono rotte (male) quando si sono verificate eccezioni.

Una "killer app" per un'API di coroutine basata su fibre è la programmazione di giochi; certi tipi di intelligenza artificiale richiedono un thread "leggero" che puoi affiancare a piacimento. Ad esempio, gli alberi di comportamento del gioco richiedono la capacità di "pulsare" il codice decisionale su ogni fotogramma, consentendo al codice AI di ritornare in modo cooperativo al chiamante quando la porzione decisionale è attiva. Questo è possibile implementare con hard thread, ma molto, molto più complicato.

Così, mentre i casi reali di utilizzo delle fibre non sono mainstream, esistono sicuramente, e una piccola nicchia di noi. I codificatori netti si rallegravano potentemente se i bug esistenti nel sottosistema di fibre venissero elaborati.

1

In realtà .NET non crea "assunzioni errate" sull'affinità del thread, infatti disaccoppia totalmente la nozione di un thread di livello .NET dal thread di livello OS.

Quello che devi fare è associare uno stato di thread .NET logico con la tua fibra (per questo hai bisogno delle CLR Hosting API ma non hai bisogno di scrivere un host tu puoi usare quelli necessari direttamente dalla tua applicazione) e tutto, il rilevamento dei blocchi, la gestione delle eccezioni funziona di nuovo normalmente.

Un esempio può essere trovato qui: http://msdn.microsoft.com/en-us/magazine/cc164086.aspx

Btw Mono 2.6 contiene partire supporto coroutine livello e può essere utilizzato per attuare tutte le primitive di livello superiore facilmente.

0

Bene, ho provato a sviluppare una libreria completa per gestire le coroutine con un solo thread. La parte difficile è stata quella di chiamare le coroutine all'interno delle coroutine ... e di restituire i parametri, ma alla fine ho raggiunto un buon risultato here. L'unico avvertimento è che il blocco delle operazioni di I/O deve essere eseguito tramite le attività e alll "return" deve essere sostituito con "yield return". Con il server delle applicazioni basato su questa libreria sono stato in grado di raddoppiare quasi le richieste effettuate con un async/atteso standard basato su IIS. (Cerca Node.Cs e Node.Cs.Musicstore su github per provarlo a casa)