J'ai une sorte de gestionnaire de travail dans C# qui recevra des tâches à faire et il va les exécuter. La tâche arrivera de différents threads, mais ils doivent être exécutés seulement un en même temps dans l'ordre où ils ont été reçus. Je ne veux pas de boucle while, qui sera exécutée tout le temps, en vérifiant s'il s'agit de nouvelles tâches dans la file d'attente. Y a-t-il une file d'attente intégrée ou un moyen facile d'implémenter une file d'attente qui attendra les tâches et les exécutera de façon synchrone sans attendre?File d'attente thread-safe avec des tâches
Répondre
Selon les commentaires que vous devriez regarder dans ConcurrentQueue mais aussi BlockingCollection et utiliser GetConsumingEnumerable() au lieu de la boucle indésirable while
BlockingCollection<YourClass> _collection =
new BlockingCollection<YourClass>(new ConcurrentQueue<YourClass>());
_collection.Add() can be called from multiple threads
sur un thread séparé, vous pouvez utiliser
foreach (var message in _collection.GetConsumingEnumerable())
{}
La demande est de le faire en même temps –
Sa phrase n'est pas claire "mais ils ne doivent être exécutés qu'un seul à la fois". Je suppose qu'il veut qu'ils soient exécutés un à la fois d'une manière séquentielle –
"mais ils doivent être exécutés ** un seul ** en même temps" –
Vous pouvez utilisez un SemaphoreSlim (https://msdn.microsoft.com/en-us/library/system.threading.semaphoreslim(v=vs.110).aspx) et une queue concurrente
Exemple:
private delegate void TaskBody();
private class TaskManager
{
private ConcurrentQueue<TaskBody>
TaskBodyQueue = new ConcurrentQueue<TaskBody>();
private readonly SemaphoreSlim
TaskBodySemaphoreSlim = new SemaphoreSlim(1, 1);
public async void Enqueue(TaskBody body)
{
TaskBodyQueue.Enqueue(body);
await TaskBodySemaphoreSlim.WaitAsync();
Console.WriteLine($"Cycle ...");
if (TaskBodyQueue.TryDequeue(out body) == false) {
throw new InvalidProgramException($"TaskBodyQueue is empty!");
}
body();
Console.WriteLine($"Cycle ... done ({TaskBodyQueue.Count} left)");
TaskBodySemaphoreSlim.Release();
}
}
public static void Main(string[] args)
{
var random = new Random();
var tm = new TaskManager();
Parallel.ForEach(Enumerable.Range(0, 30), async number => {
await Task.Delay(100 * number);
tm.Enqueue(delegate {
Console.WriteLine($"Print {number}");
});
});
Task
.Delay(4000)
.Wait();
WaitFor(action: "exit");
}
public static void WaitFor(ConsoleKey consoleKey = ConsoleKey.Escape, string action = "continue")
{
Console.Write($"Press {consoleKey} to {action} ...");
var consoleKeyInfo = default(ConsoleKeyInfo);
do {
consoleKeyInfo = Console.ReadKey(true);
}
while (Equals(consoleKeyInfo.Key, consoleKey) == false);
Console.WriteLine();
}
Merci. Cela ressemble à une bonne solution, mais BlockingCollection semble être plus facile et plus simple pour ce problème. – user3126358
Je ne pense pas qu'il y ait construire fonctionnalité pour ce modèle mais vous pouvez construire un sans en boucle à travers ** SemaphoreSlim ** –
Avez-vous vérifié [ConcurrentQueue] (https://msdn.microsoft.com/ fr-fr/library/dd267265 (v = vs.110) .aspx) et/ou [Queue.Synchronized] (https://msdn.microsoft.com/fr-fr/library/system.collections.queue.synchronized (v = vs.110) .aspx)? –
Hintham
TPL Dataflow est une solution, compte tenu de votre exigence selon laquelle il ne fonctionne pas tout le temps. Vous pouvez contrôler comment il est exécuté (en termes de threads, etc.), donc je pense que vous devriez être en mesure de vous assurer qu'un seul s'exécute à la fois. Attention, vous ne créez pas de backlog cependant. – john