Conversione di asincronia basata su eventi in C # 5 asincrona

3

Al momento disponiamo di un'interfaccia per un decodificatore video asincrono che gira su una propria thread. Fondamentalmente gli dai dei dati e alla fine ti richiamerà sul suo thread attraverso alcuni eventi, come in questo caso (non vero codice):

interface IDecoder {
    void Decode(parameters);
    event FrameReady;
    event FrameDropped;
    // lots of other possibilities
}

È un po 'complicato e mi piacerebbe convertirlo in un C # 5, versione basata su async, qualcosa del tipo:

interface IDecoder {
    async Task<DecodeResult> DecodeAsync(parameters);
}

Dove DecodeResult avrà tutte le informazioni che altrimenti sarebbero state trasmesse tramite eventi, e il codice cliente può essere scritto in modo pulito con asincrono / attesa piuttosto che un pasticcio di gestori di eventi e invio di thread.

Comprendo che Task è pianificato sul ThreadPool per impostazione predefinita. Vogliamo che tutte le operazioni di decodifica avvengano in sequenza su un singolo thread specifico del decodificatore. Questo può essere ottenuto usando Task, se sì, come? Le attività sono appropriate anche per questo uso o c'è uno schema più ovvio che mi manca?

    
posta Asik 08.03.2014 - 07:34
fonte

2 risposte

2

It is my understanding that Tasks are scheduled on the ThreadPool by default.

Task s creati usando Task.Run() (o Task.Factory.StartNew() , nel caso comune) lo sono. Ma questo non si applica a Task s che non esegue alcun codice, come quelli creati automaticamente dai metodi async , o quelli creati usando TaskCompletionSource .

Quindi, quello che vuoi è certamente possibile. Quanto esattamente farlo dipende da cosa dovrebbe fare DecodeAsync() .

EDIT: probabilmente il modo più semplice per convertire il tuo codice corrente in Task s sarebbe utilizzando TaskCompletionSource . Chiama semplicemente TaskCompletionSource.SetResult() invece di invocare un evento.

Ma un'altra opzione potrebbe essere qualcosa del tipo:

class Decoder : IDecoder
{
    // initialize with a completed Task
    Task previous = Task.FromResult(true);

    public Task<DecodeResult> DecodeAsync(parameters)
    {
        var result = DecodeAsyncInternal(parameters);
        previous = result;
        return result;
    }

    private async Task<DecodeResult> DecodeAsyncInternal(parameters)
    {
        await previous;
        return await Task.Run(() => ActualDecode(parameters));
    }
}

Questo non garantisce che tutta la decodifica avvenga sullo stesso thread, ma garantisce che i lavori vengano eseguiti uno dopo l'altro.

Inoltre, questo codice non è thread-safe: non funzionerà correttamente se chiama DecodeAsync() allo stesso tempo da più thread. Se ti serve, usa un lucchetto.

    
risposta data 08.03.2014 - 16:02
fonte
2

Potresti implementare un TaskScheduler personalizzato allo scopo di alimentare solo un thread con il lavoro delle attività come puoi vedere su MSDN - Procedura: creare un Utilità di pianificazione che limiti la concorrenza

In rare scenarios, you might be able to achieve a performance speedup by creating a custom task scheduler that is derived from the System.Threading.Tasks.TaskScheduler class. You can then specify this scheduler by supplying a ParallelOptions object to an overload of the For or ForEach method. When you use Task objects directly, you can specify the custom scheduler by using the TaskFactory constructor that takes a TaskScheduler as an input parameter, or by some other means such as TaskFactory.StartNew.

You can also use a custom scheduler to achieve functionality that the default scheduler does not provide, such as strict first-in, first-out (FIFO) execution order...

    
risposta data 08.03.2014 - 11:19
fonte

Leggi altre domande sui tag