Implementazione di 'soltanto una delle' e 'non in parallelo' semantica con la libreria in parallelo Task

StackOverflow https://stackoverflow.com/questions/3613812

  •  26-09-2019
  •  | 
  •  

Domanda

Quale sarebbe l'approccio migliore per le attività con una chiave che operano come attuazione segue: -

L'opzione 1) Solo uno di questa chiave è sempre in attesa. Può essere utilizzato, ad esempio, da ASP.NET MVC in fila una sola di rendering per una miniatura non importa quante volte l'immagine URL viene colpito. Solo uno corre, tutte le altre richieste aspettano quello di completa.

L'opzione 2) Tutti gli articoli con la stessa chiave deve eseguire in sequenza. Può essere usato ad esempio per garantire che le operazioni che recuperano un file da un archivio di backup a una cache locale non tutti cercano di ottenere il file nella cache allo stesso tempo. Opzione 1 è un caso speciale di questo, dove le azioni successive con la stessa chiave sono semplicemente scartati (tipicamente salva solo un file-esiste-check).

Ho un WorkQueue esistente che manici entrambi i casi (come pure Appartamento di stato, le impostazioni ThreadPriority e massimi gradi di parallelismo). TPL sembra essere la soluzione migliore per la sostituzione di questo e porterà migliorate le opzioni di cancellazione.

Attività annidate con continuazioni sguardo speranzoso, ma il mantenimento di un dizionario dei compiti attualmente queue'd ottiene presto disordinato tra il TaskFactory e le classi TaskScheduler. Ereditando da Task è problematica poiché né troppo né TaskFactory TaskScheduler sono generici sul compito.

La maggior parte Task Parallel esempi presuppongono che l'insieme di attività è nota prima del tempo. In questo caso vengono aggiunti nuovi compiti per tutto il tempo e la necessità di essere eliminate o incatenato su attività esistenti a seconda l'operazione richiesta e la chiave passata.

Qualcuno ha implementato qualcosa di simile a questo con TPL e in caso affermativo, quale approccio Hai preso nel vostro compito, TaskScheduler e classi TaskFactory?

È stato utile?

Soluzione

Forse, in un modo che mi viene in mente è

  1. Creare una classe wrapper - dire KeyProcessor in fila gli elementi per una chiave.
  2. Metodo
  3. KeyProcessor.Run () sarà capace di qualunque semantica di accodamento che avete bisogno per. In sostanza sarebbe cercare coda interna per i lavori in sospeso e poi continuare a farlo in modo sequenziale.
  4. Mantenere il dizionario dei KeyProcessor oggetti.
  5. Per ogni nuovo compito, il check-nel dizionario per la stessa chiave. Se non esiste quindi aggiungerlo. Coda il compito su di esso. Se la sua non è in esecuzione, allora pianificare con TPL utilizzando il metodo Esegui come azione.
  6. Usa ContinueWith di pianificazione compito manutentore - per esempio, ogni volta Task esecuzione KeyProcessor.Run è completato, i compiti di continuazione possono verificare se sono presenti più attività state programmate per la stessa chiave (poiché è completato) e iniziare nuovamente o rimuovi da dizionario.

Tutti sopra sarebbe stato difficile da filo punto di sincronizzazione non per alcune collezioni presenti nel System.Collections.Concurrent namespace. Ciò renderebbe la logica di cui sopra molto più semplice. Ad esempio, ConcurrentDictionary.GetOrAdd permetterà di ricercare e / o aggiungere l'oggetto KeyProcessor in modo thread-safe.

Altri suggerimenti

Il problema è simile a quella che ho risolto in ReactiveXaml , anche se la mia anche memoized richieste precedenti. Date un'occhiata al codice per QueuedAsyncMRUCache (e la sua blog ) - questo codice unisce il TPL con le estensioni del reattivi per ottenere questo tipo di cosa fatta, ma rende la garanzia importante che il 2 ° richiesta per la stessa chiave bloccherà alla prima richiesta in volo, invece di l'emissione di un altro.

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