La mise en œuvre « un seul des » et « non en parallèle » sémantique avec la bibliothèque parallèle de tâches

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

  •  26-09-2019
  •  | 
  •  

Question

Quelle serait la meilleure approche pour la mise en œuvre des tâches avec une clé qui fonctionnent comme suit: -

Option 1) Une seule de cette clé est toujours en suspens. Peut être utilisé, par exemple, de ASP.NET MVC faire la queue un rendu pour une image miniature, peu importe combien de fois l'image Url est touché. Un seul fonctionne, toutes les autres demandes attendent que l'on à remplir.

Option 2) Tous les articles avec la même clé doit exécuter de manière séquentielle. Peut être utilisé par exemple pour faire en sorte que les opérations qui vont chercher un fichier à partir d'un magasin de support à un cache local ne sont pas tous essayer d'obtenir le fichier dans le cache en même temps. Option 1 est un cas particulier de celui-ci où les actions ultérieures avec la même clé sont simplement mis au rebut (enregistre généralement juste un fichier existe vérification).

J'ai un WorkQueue existant qui gère ces deux cas (ainsi que l'état de l'appartement, les paramètres ThreadPriorité et degrés de parallélisme maximum). TPL semble être la meilleure solution pour remplacer cela et apportera de meilleures options d'annulation.

emboîtées tâches avec continuations regard plein d'espoir, mais maintenant un dictionnaire des tâches actuellement queue'd va très vite entre le désordre TaskFactory et les classes TaskScheduler. Héritant de la tâche est problématique puisque ni trop, ni TaskFactory TaskScheduler sont génériques sur la tâche.

La plupart des exemples de tâches parallèles supposent que l'ensemble des tâches est connue à l'avance. Dans ce cas, de nouvelles tâches sont ajoutées tout le temps et doivent être soit mis au rebut ou enchaîné sur des tâches existantes en fonction de l'opération demandée et la clé transmise.

Quelqu'un at-il mis en œuvre quelque chose de semblable à cela en utilisant TPL et si oui, quelle approche avez-vous pris dans votre tâche, les classes TaskScheduler et taskFactory?

Était-ce utile?

La solution

Peut-être, d'une manière que je peux penser est

  1. Créer une classe wrapper - dire KeyProcessor à faire la queue des éléments pour une clé.
  2. méthode KeyProcessor.Run () sera capable de faire la queue quelle que soit la sémantique que vous avez besoin pour. Essentiellement, il rechercherait file d'attente interne pour tout travail en attente et continuer à le faire de manière séquentielle.
  3. Maintenir le dictionnaire d'objets KeyProcessor.
  4. Pour toute nouvelle tâche, vérifier dans le dictionnaire pour la même clé. Si ne puis existe pas ajouter. File d'attente la tâche sur elle. Si ce ne est pas en cours d'exécution puis planifiez avec TPL en utilisant la méthode Exécuter en tant action.
  5. Utilisez ContinueWith pour planifier la tâche du responsable - par exemple, chaque fois que la tâche d'exécuter KeyProcessor.Run est terminée, les tâches de continuation peuvent vérifier s'il y a des tâches plus été programmées pour la même clé (puisqu'il a terminé) et recommencer à nouveau ou supprimer du dictionnaire.

Tous ci-dessus aurait été difficile du point de synchronisation de fil non pour quelques collections intéressantes présentes dans l'espace de noms de System.Collections.Concurrent. Cela rendrait la logique ci-dessus beaucoup plus simple. Par exemple, ConcurrentDictionary.GetOrAdd permettra de rechercher et / ou ajouter l'objet KeyProcessor de manière thread-safe.

Autres conseils

Ce problème est similaire à celui que je résolu dans ReactiveXaml , mais aussi le mien memoized demandes antérieures. Jetez un oeil au code QueuedAsyncMRUCache (et son entrée de blog ) - ce code combine le TPL avec les extensions réactives pour obtenir ce genre de chose fait, mais il est la garantie importante que la 2ème demande de la même clé bloque sur la première demande en vol au lieu de émission d'une autre.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top