Domanda

Attualmente, ho un gran numero di C # calcoli (chiamate di metodo) che risiedono in una coda che verrà eseguito in sequenza. Ogni calcolo utilizzerà parte alta latenza servizio (rete, disco ...).

Stavo per usare coroutine Mono per consentire il successivo calcolo in coda calcolo di continuare mentre un calcolo precedente è in attesa per il servizio di alta latenza di tornare. Tuttavia, preferisco non dipendere da coroutine Mono.

C'è un modello di progettazione che è implementabile in puro C # che mi consenta di elaborare calcoli supplementari durante l'attesa per i servizi ad alta latenza per tornare?

Grazie

Aggiornamento:

Ho bisogno di eseguire un numero enorme (> 10000) di attività e ogni attività verrà utilizzato un po 'di un servizio di alta latenza. Su Windows, non è possibile creare più di tanto le discussioni.

Aggiornamento:

In sostanza, ho bisogno di un modello di progettazione che emula i vantaggi (come segue) di tasklets in Stackless Python ( http: // www.stackless.com/ )

  1. enorme # di compiti
  2. Se un blocchi di attività il prossimo compito in coda esegue
  3. ciclo della CPU No sprecato
  4. Minimal commutazione testa tra compiti
È stato utile?

Soluzione

È possibile simulare microthreading cooperativa utilizzando IEnumerable. Purtroppo questo non funzionerà con il blocco API, quindi è necessario trovare le API che è possibile interrogare, o che hanno callback che è possibile utilizzare per la segnalazione.

Si consideri un metodo

IEnumerable Thread ()
{
    //do some stuff
    Foo ();

    //co-operatively yield
    yield null;

    //do some more stuff
    Bar ();

    //sleep 2 seconds
    yield new TimeSpan (2000);
}

Il compilatore C # sarà scartare questo in una macchina a stati -. Ma l'aspetto è quello di un MicroThread cooperativa

Lo schema è abbastanza semplice. Si implementa un "scheduler" che mantiene un elenco di tutte le IEnumerators attivi. In quanto i cicli attraverso la lista, "corre" ognuno con MoveNext (). Se il valore di MoveNext è falso, il thread è terminato, e lo scheduler lo rimuove dalla lista. Se è vero, allora lo scheduler accede alla proprietà attuale per determinare lo stato corrente del thread. Se si tratta di un periodo, il filo vuole dormire, e lo scheduler spostato su qualche coda che può essere lavata di nuovo nella lista principale quando i timespans sonno sono finiti.

È possibile utilizzare altri oggetti di ritorno per implementare altri meccanismi di segnalazione. Ad esempio, definire una sorta di WaitHandle. Se il filo produce uno di questi, può essere spostato in una coda di attesa finché la maniglia viene segnalato. Oppure si potrebbe sostenere WaitAll cedendo una serie di maniglie di attesa. Si potrebbe anche realizzare le priorità.

Ho fatto una semplice implementazione di questo scheduler in circa 150LOC ma non ho avuto intorno a bloggare il codice ancora. E 'stato per il nostro involucro PhyreSharp PhyreEngine (che non sarà pubblico), dove sembra funzionare abbastanza bene per il controllo di un paio di centinaia di personaggi in uno dei nostri demo. Abbiamo preso in prestito il concetto del motore Unity3D - hanno alcuni documenti online che spiegano da un punto di vista dell'utente

.

Altri suggerimenti

Mi consiglia di utilizzare la pool di thread per eseguire più attività dalla coda in una sola volta in lotti gestibili utilizzando un elenco di attività attive che si nutre della coda compito.

In questo scenario la principale thread di lavoro avrebbe inizialmente pop compiti N dalla coda nella lista compiti attiva, viene inviato al pool di thread (molto probabilmente utilizzando QueueUserWorkItem ), dove N rappresenta una quantità gestibile che non sovraccaricare il pool di thread, palude vostra applicazione verso il basso con filo costi di programmazione e sincronizzazione, o aspirare memoria disponibile a causa della memoria sovraccarico combinato I / o di ogni attività.

Ogni volta che un completamento segnali di attività per il thread di lavoro, è possibile rimuoverlo dalla lista task attivi e aggiungere il successivo dalla coda compito da eseguire.

Questo vi permetterà di avere un set di rotolamento di compiti N dalla coda. È possibile manipolare N per influenzare le caratteristiche di prestazione e trovare ciò che è meglio nelle vostre circostanze particolari.

Dal momento che sono in ultima analisi, un collo di bottiglia per le operazioni di hardware (disco I / O e la rete di I / O, CPU) immagino più piccolo è meglio. Due compiti pool di thread che lavorano su disco I / O molto probabilmente non verrà eseguito più velocemente di uno.

Si potrebbe anche implementare flessibilità nelle dimensioni e contenuto dell'elenco dei task attivi, limitando ad un determinato numero di particolare tipo di compito. Per esempio se si esegue su una macchina con 4 core, si potrebbe scoprire che la configurazione di esecuzione più alta è di quattro attività della CPU-bound in esecuzione contemporaneamente insieme a un compito del disco-bound e un compito di rete.

Se si dispone già di un compito classificato come un compito IO disco, si può scegliere di attendere che sia completo prima di aggiungere un altro compito IO disco, e si può scegliere di pianificare un'operazione CPU-bound o di rete-bound nel frattempo .

Spero che questo ha un senso!

PS:? Avete qualche dipendenze dell'ordine di attività

Si dovrebbe verificare la Concurrency Runtime e coordinamento . Uno dei loro campioni descrive esattamente cosa si sta parlando: si chiama fuori per servizi a lungo di latenza, e il CCR permette in modo efficiente qualche altro compito di correre, mentre si attende. E 'in grado di gestire gran numero di compiti, perché non ha bisogno di generare un thread per ciascuno di essi, anche se sarà utilizzare tutti i core se chiedete a.

Non è questo un uso convenzionale di elaborazione multi-threaded?

Date un'occhiata a modelli come Reactor qui

Scrittura in modo da utilizzare IO asincrono potrebbe essere sufficiente.

Questo può portare a nasy, difficile da eseguire il debug di codice senza una forte struttura nel disegno.

Si dovrebbe dare un'occhiata a questo:

http://www.replicator.org/node/80

Questo dovrebbe fare esattamente quello che vuoi. Si tratta di un hack, però.

Alcuni ulteriori informazioni sul modello "a caldo" (come detto da un altro poster) rispetto ad un'implementazione in .NET; alias "LINQ to Events"

http://themechanicalbride.blogspot.com /2009/07/introducing-rx-linq-to-events.html

-Oisin

In realtà, se si utilizza un thread per un compito, si perde la partita. Riflettere sul perché Node.js in grado di supportare il numero enorme di conections. Utilizzo di un limitato numero di filo con async IO !!! Async e attendono funzioni possono aiutare in questo.

foreach (var task in tasks)
{
    await SendAsync(task.value);
    ReadAsync(); 
}

SendAsync () e ReadAsync () sono funzioni falsificate per IO asincrono chiamata.

Task parallelismo è anche una buona scegliere. Ma io non sono sicuro che uno è più veloce. È possibile verificare entrambi nel tuo caso.

Sì, naturalmente è possibile. Hai solo bisogno di costruire un meccanismo di dispatcher che chiamerà indietro su una lambda che fornite e va in una coda. Tutto il codice che scrivo in unità utilizza questo approccio e non ho mai uso coroutine. Mi avvolgo metodi che utilizzano coroutine come roba WWW per ottenere solo liberarsi di esso. In teoria, coroutine possono essere più veloce perché c'è meno overhead. Praticamente introducono nuova sintassi per un linguaggio per fare un compito abbastanza banale e, inoltre, non è possibile seguire la traccia dello stack correttamente su un errore in un co-routine di perché tutto quello che vedrete è -> Avanti. Dovrete quindi implementare la possibilità di eseguire i compiti in coda su un altro thread. Tuttavia, c'è funzioni parallele nella sua ultima .net e vi sarebbe stato essenzialmente scrivendo una funzionalità simile. Non sarebbe molte righe di codice davvero.

Se qualcuno è interessato mi inviare il codice, non hanno su di me.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top