Le meilleur moyen de .NET pour gérer la file d'attente des tâches sur un thread séparé (unique)
Je sais que la programmation asynchrone a vu beaucoup de changements au fil des ans. Je suis un peu gêné que je me laisse cette rouillé à tout juste 34 ans, mais je compte sur StackOverflow me conduire jusqu'à la vitesse.
Ce que j'essaie de faire, c'est gérer une file d'attente de "travail" sur un thread séparé, mais de telle manière que seul un élément est traité à la fois. Je veux travail de post sur ce fil et il n'a pas besoin de passer quelque chose à l'appelant. Bien sûr, je pourrais simplement tourner une nouvelle Thread
objet et l'avoir en boucle sur un partagées Queue
objet, à l'aide dort, interruptions, attendre poignées, etc. Mais je sais que les choses se sont bien améliorés depuis. Nous avons BlockingCollection
Task
async
/await
pour ne pas mentionner les packages NuGet qui est probablement à l'abstrait en a beaucoup.
Je sais que "Ce qui est le meilleur..." des questions sont généralement mal vu alors je vais reformuler en disant: "qu'est-Ce que le traitement actuellement recommandé..." moyen d'accomplir quelque chose comme ceci à l'aide intégrée dans .NET mécanismes de préférence. Mais si un tiers de package NuGet simplifie les choses un tas, c'est tout aussi bien.
- Je considéré comme un TaskScheduler
exemple avec un fixe de la concurrence maximale de 1, mais il semble qu'il y a probablement beaucoup moins maladroit façon de le faire maintenant.
Fond
Plus précisément, ce que je suis en train de faire dans ce cas est la file d'attente d'une géolocalisation IP tâche lors d'une requête web. De la même IP peut se retrouver en file d'attente pour l'obtention de la géolocalisation plusieurs fois, mais la tâche sera de savoir comment faire pour détecter et sauter plus tôt si ça a déjà été résolu. Mais le gestionnaire de requêtes va juste jeter ces () => LocateAddress(context.Request.UserHostAddress)
appels en file d'attente et de laisser le LocateAddress
méthode de gérer un double travail de détection. L'API de géolocalisation, je suis en utilisant n'aime pas être bombardés de demandes, ce qui est pourquoi je tiens à le limiter à une seule concurrente tâche à la fois. Cependant, il serait agréable si l'approche a permis d'évoluer facilement pour plus de tâches simultanées avec un simple changement de paramètre.
source d'informationauteur Josh
Vous devez vous connecter pour publier un commentaire.
Pour créer un asynchrones seul degré de parallélisme de la file d'attente de travail, vous pouvez simplement créer un
SemaphoreSlim
initialisé à un, puis le enqueing méthodeawait
sur l'acquisition de ce sémaphore avant de commencer le travail demandé.Bien sûr, d'avoir un degré de parallélisme autre que l'une consiste à initialiser le sémaphore à un autre numéro.
Votre meilleure option que je vois c'est à l'aide de
TPL Dataflow
'sActionBlock
:TPL Dataflow
est robuste, thread-safe,async
-prêt et très configurable acteur à base de cadre (disponible en nuget)Voici un exemple simple pour un cas plus compliqué. Supposons que vous voulez:
LocateAddress
et la file d'attente d'insertionasync
.Utilisation
BlockingCollection<Action>
pour créer un producteur/consommateur modèle avec un consommateur (la seule chose qui exécute à un moment comme vous voulez) et un ou plusieurs producteurs.D'abord définir une file d'attente partagée quelque part:
Dans votre consommation
Thread
ouTask
vous prenez à partir de:Puis, à partir de n'importe quel nombre de producteurs sur d'autres threads, il suffit d'ajouter à la file d'attente:
Fait, vous n'avez pas besoin d'exécuter des tâches dans un thread, vous en avez besoin pour exécuter en série (l'un après l'autre), et FIFO. TPL n'a pas de classe, mais voici ma mise en œuvre avec des tests. https://github.com/Gentlee/SerialQueue
Ont aussi @Servy de mise en œuvre il y a, les tests montrent qu'il est deux fois plus lent que le mien et il n'a pas de garantie FIFO.
Exemple: