De la tâche.WaitAll() ne fonctionne pas comme prévu
Je suis à essayer de comprendre comment travailler avec le groupe classe. Dans le passé, j'ai toujours utilisé le régulier de la classe Thread, mais j'essaie de saisir l'ensemble de la programmation asynchrone...
Comme un exemple, j'ai créé l'un des principaux Winforms application qui dispose de tous le code.
Le code pour mon problème est:
//Relevant delegates
public delegate void MethodAction(int num);
public delegate void MethodConversion();
public delegate void OnCompletionAction(string completiontext);
//Button user presses
private void button4_Click(object sender, EventArgs e)
{
richTextBox1.Clear();
sw.Reset();
sw.Start();
Sync.RunAsync3(calcSim);
}
//The method that simulates a calculation by adding a sleep
//the input param threadlength is just to allow threads to take longer than others
//since I'm multithreading, I have to invoke the writing code on the windows RichTextbox control
private void calcSim(int threadlength)
{
string threadname = Thread.CurrentThread.Name;
for (int i = 0; i < 10; i++) //Thread calc should take 3s
{
Thread.Sleep(300 + threadlength);
richTextBox1.Invoke((MethodConversion)(() =>
{
richTextBox1.AppendText(string.Format("Thread: {0}\tVersion: {1}\n", threadname, (i + 1).ToString()));
}));
}
}
//Class that contains the different processing methods
public static class Sync
{
public static event OnCompletionAction OnProcCompletion;
public static void RunAsync3(MethodAction doM)
{
Task[] t = new Task[4];
for(int i = 0; i < 4; i++)
{
t[i] = Task.Factory.StartNew((Action)(() => { doM(50 * i); }));
}
Task.WaitAll(t);
if (OnProcCompletion != null) OnProcCompletion("RunSync method finished");
}
}
Le problème réside dans la Tâche.WaitAll(t)... Pour une raison que je ne peux pas comprendre, elle bloque complètement sur cette ligne et ne répond plus. Si je omettre la ligne, la forme est mise à jour en temps réel et l'exécution dure environ 3 secondes.
Ma question est: pourquoi n'est-ce pas la Tâche.WaitAll() bloque le thread d'INTERFACE utilisateur pour 3 secondes avant de le relâcher et permettant le reste du code à exécuter?
Je sais que ça doit être le blocage de l'INTERFACE utilisateur pour un certain temps (jusqu'à ce que tous les threads de calcul), mais elle bloque la complète des applications à l'infini. Il semble être en attente pour toujours?
MODIFIER
J'ai été suggéré d'utiliser WhenAll au lieu de WaitAll. J'ai réécrit RunAsync3 comme suit:
public static void RunAsync3(MethodAction doM)
{
Task[] t = new Task[4];
for(int i = 0; i < 4; i++)
{
t[i] = Task.Factory.StartNew((Action)(() => { doM(50 * i); }));
}
//Task.WaitAll(t); -> deadlock
Task.WaitAll(new Task [] { Task.WhenAll(t) });
if (OnProcCompletion != null) OnProcCompletion("RunSync method finished");
}
Mais c'est toujours dans l'impasse...? Je suis peut-être à l'aide de la WhenAll mal?
EDIT 2
Parce que tout le monde en déclarant que j'étais bloquer le thread de l'INTERFACE utilisateur ont été à droite, j'ai décidé d'essayer cette autre manière: en cours d'exécution d'un thread que mon thread appelant à l'intérieur de la thread d'INTERFACE utilisateur (de sorte que le blocage de maintenant se ferait sur mon thread au lieu de thread d'INTERFACE utilisateur). Cela fonctionne, mais n'est évidemment pas la meilleure façon de le faire!
private void button4_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(() =>
{
richTextBox1.Invoke((MethodConversion)(() => richTextBox1.Clear()));
sw.Reset();
sw.Start();
Sync.RunAsync3(calcSim);
}));
t.Start();
}
public static void RunAsync3(MethodAction doM)
{
Task[] t = new Task[4];
for(int i = 0; i < 4; i++)
{
t[i] = Task.Factory.StartNew((Action)(() => { doM(50 * i); }));
}
Task.WaitAll(t);
//Task.WaitAll(new Task [] { Task.WhenAll(t) });
if (OnProcCompletion != null) OnProcCompletion("RunSync method finished");
}
Je sais que ça doit bloquer le thread d'INTERFACE utilisateur, qui n'est pas le problème. Le problème est qu'il n'a jamais continue avec le reste du code. Il semble que c'est l'attente interminable!
Puisque vous essayez de "Invoquer" quelque chose sur le thread principal qui est dans un waitstate, à partir d'un travailleur?
Vous devriez envisager de
await Task.WhenAll(...);
Une alternative serait de pousser les actions que vous faites sur une pile, et après la waitall (qui sera alors le travail puisque vous n'êtes pas d'essayer d'appeler le thread principal est plus pop & exécuter la construction de la pile
OriginalL'auteur Recipe | 2013-11-04
Vous devez vous connecter pour publier un commentaire.
Vous êtes à l'origine du blocage.
Le thread d'INTERFACE utilisateur est en attente pour les 4 tâches à accomplir.
D'autre part, ces 4 tâches, l'exécution de
calcSim
tentent d'invoquer le code sur le thread d'INTERFACE utilisateur -> Blocage.Vous devriez être en utilisant
Task.WhenAll()
à la place. Cette méthode retourne une nouvelle tâche qui sera marquée comme terminée lorsque tous votre pour les tâches accomplies. Si vous attendez de cette tâche, votre thread de l'INTERFACE utilisateur sera libéré, et ainsi decalcSim
sera en mesure d'invoquer le code sur le thread de l'INTERFACE utilisateur, en évitant un blocage.Mise à jour
Vous l'utilisez mal. Vous êtes toujours à l'aide de
WaitAll
, qui est un appel bloquant. Vous devriez remplacer avecWhenAll
.De la la documentation:
En appelant
await
sur le résultat, votre thread de l'INTERFACE utilisateur sera libre jusqu'à ce que tous les 4 tâches sont terminées. Lorsque cela se produit, votreRunAsync3
méthode va reprendre.J'ai édité ma réponse avec un éventuel correctif. Permettez-moi de savoir comment il va.
Je suis toujours dans l'impasse... j'ai mis à jour ma question avec mes tentatives que vous avez suggéré, mais tout reste bloqué... je suis peut-être à l'aide de WhenAll mal?
J'ai édité ma réponse, là encore, il devrait être plus clair maintenant.
Parfait! J'espérais omettre l'async & attendent les mots-clés jusqu'à ce que j'ai compris de la Tâche, de pool de threads et Parallèles, mais dans ce cas, je ne pense pas qu'il y a un moyen de contourner cela. Je vais donner la réponse.
OriginalL'auteur dcastro
Task.WaitAll
bloque et attend pour l'ensemble de la tâche à accomplir et vous appelez ça sur le thread d'INTERFACE utilisateur.Toutes vos tâches sont d'essayer d'appeler
richTextBox1.Invoke
(dans le thread de l'INTERFACE utilisateur), mais votre thread de l'INTERFACE utilisateur est bloqué dansTask.WaitAll
. L'impasse.OriginalL'auteur Alberto
Car il attend que votre fils finition. Ils fonctionnent exactement 3 secondes 300X10
OriginalL'auteur dblk1965