Pourquoi ce code Parallel.ForEach gèle-t-il le programme?
Plus des questions de newbie:
Ce code attrape un certain nombre de procurations de la liste dans la fenêtre principale (je ne pouvais pas comprendre comment faire de variables disponibles entre les différentes fonctions) et effectue une vérification sur chacun (simple httpwebrequest) et puis les ajoute à une liste appelée finishedProxies.
Pour quelque raison que quand j'appuie sur le bouton de démarrage, l'ensemble du programme se bloque en place. J'étais sous l'impression que le Parallèle crée des threads séparés pour chaque action, laissant le thread d'INTERFACE utilisateur seulement, de sorte qu'il est sensible?
private void start_Click(object sender, RoutedEventArgs e)
{
//Populate a list of proxies
List<string> proxies = new List<string>();
List<string> finishedProxies = new List<string>();
foreach (string proxy in proxiesList.Items)
{
proxies.Add(proxy);
}
Parallel.ForEach<string>(proxies, (i) =>
{
string checkResult;
checkResult = checkProxy(i);
finishedProxies.Add(checkResult);
//update ui
/*
status.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal,
new Action(
delegate()
{
status.Content = "hello" + checkResult;
}
)); */
//update ui finished
//Console.WriteLine("[{0}] F({1}) = {2}", Thread.CurrentThread.Name, i, CalculateFibonacciNumber(i));
});
}
J'ai essayé d'utiliser le code est commenté pour apporter des modifications à l'INTERFACE utilisateur à l'intérieur de la Parallèle.Foreach et il rend le programme gel après le bouton de démarrage est enfoncé. Il a travaillé pour moi avant, mais j'ai utilisé de la classe Thread.
Comment puis-je mettre à jour l'INTERFACE utilisateur de l'intérieur de la Parallèle.Foreach et comment puis-je faire en Parallèle.Foreach travail, afin de ne pas rendre l'INTERFACE de gel alors que cela fonctionne?
source d'informationauteur dsp_099
Vous devez vous connecter pour publier un commentaire.
Vous ne devez pas commencer le traitement parallèle dans votre thread de l'INTERFACE utilisateur. Voir l'exemple dans le cadre du "Éviter l'Exécution de Boucles Parallèles sur le Thread d'INTERFACE utilisateur" tête dans cette page.
Mise à jour: Ou, vous pouvez simplement créer un nouveau thread manuall et de commencer le traitement à l'intérieur que je vois que vous avez fait. Il n'y a rien de mal à cela aussi.
Aussi, comme Jim Mischel points, vous avez accès à des listes à partir de plusieurs threads en même temps, il y a donc des conditions de course. Soit remplacer
ConcurrentBag
pourList
ou enveloppez-les listes à l'intérieur d'unlock
déclaration chaque fois que vous y accédez.Un bon moyen de contourner les problèmes de ne pas être capable d'écrire sur le thread de l'INTERFACE utilisateur lors de l'utilisation en Parallèle des déclarations est d'utiliser la Tâche de l'Usine et des délégués, voir le code suivant, je l'utilise pour effectuer une itération sur une série de fichiers dans un répertoire, et les proces en parallèle d'une boucle foreach, après chaque dossier est traité de la thread de l'INTERFACE utilisateur en est averti et mise à jour:
Et les méthodes que les changements de l'INTERFACE:
Espérons que cette aide!
Si quelqu'un est curieux, j'ai un peu pensé à elle, mais je ne suis pas sûr si c'est une bonne programmation ou de tout moyen de régler le problème.
J'ai créé un nouveau fil de discussion comme suit:
et de ranger tous les parallèles choses à l'intérieur d'do_checks().
Semble correct.
Un problème avec votre code, c'est que vous êtes d'appel
FinishedProxies.Add
à partir de plusieurs threads simultanément. Qui va causer un problème parce queList<T>
n'est pas thread-safe. Vous aurez besoin de les protéger avec un verrou ou de certains autres primitives de synchronisation, ou utiliser une collecte simultanée.Si les causes de l'INTERFACE utilisateur de blocage, je ne sais pas. Sans plus d'informations, c'est difficile à dire. Si le
proxies
liste est très longue etcheckProxy
ne faut pas longtemps à s'exécuter, alors votre les tâches de la file d'attente derrière queInvoke
appel. Qui va causer tout un tas d'attente de l'INTERFACE utilisateur des mises à jour. Qui de verrouillage de l'INTERFACE utilisateur, car le thread d'INTERFACE utilisateur est occupé de l'entretien de ces demandes en file d'attente.C'est ce que je pense qui se passe dans votre base de code.
Scénario Normal : Vous cliquez sur le bouton. Ne pas utiliser en Parallèle.Boucle Foreach. Utiliser la classe Dispatcher et poussez le code à exécuter sur les thread en arrière-plan. Une fois que le thread d'arrière-plan est effectué, il invoquera le principal thread d'INTERFACE utilisateur pour la mise à jour de l'INTERFACE utilisateur. Dans ce scénario, le thread d'arrière-plan(appelé par l'intermédiaire de Dispatcher) connaît les principaux thread de l'INTERFACE utilisateur, il doit de rappel. Ou tout simplement déclaré que le principal de l'UI thread possède sa propre identité.
En Utilisant En Parallèle.Boucle Foreach : une Fois que vous invoquez Paralle.Boucle Foreach, le framework utilise le pool de threads thread. Pool de threads les threads sont choisis au hasard et l'exécution de code ne devrait jamais faire aucune hypothèse sur l'identité du thread choisi. Dans le code d'origine de sa très possible que le répartiteur fil invoqué via un port Parallèle.Boucle Foreach n'est pas en mesure de comprendre le fil qui lui est associée. Lorsque vous utilisez explicite fil, puis il fonctionne très bien parce que l'explicite thread possède sa propre identité, ce qui peut être invoqué par l'exécution du code.
Idéalement, si votre principale préoccupation est tout au sujet de l'observance de l'INTERFACE utilisateur réactive, vous devez d'abord utiliser la classe Dispatcher pour pousser le code dans le thread d'arrière-plan et alors là utiliser ce que jamais la logique que vous voulez de l'accélération de l'exécution globale.
si vous souhaitez utiliser parallèle foreach graphique de contrôle comme un clic de bouton etc
puis mettre en parallèle foreach dans la Tâche.Usine.StartNew
comme
il permettra de résoudre gel/collé ou de problème de blocage