6
votes

Comment passer des informations à partir d'un threadpool.QueueUserWorkItem retour au fil de l'interface utilisateur?

J'ai une question de filetage assez simple.

J'écris un utilitaire simple qui exécutera divers scripts SQL basés sur des paramètres définis par l'utilisateur.

Afin de conserver l'interface utilisateur réactive et de fournir des commentaires sur l'état des scripts en cours d'exécution, j'ai décidé que l'utilisation de threadpool.quaueueuerworkitem serait appropriée pour gérer l'exécution du Divers scripts (via SMO.)

Cependant, je suis un peu confus quant à la manière dont je peux relancer les informations de sortie que SMO reviendra sur le fil de l'interface utilisateur.

Pour cet utilitaire, j'utilise WPF et MVVM pour la présentation. Je pense que j'aurais une classe scriptworker que je pourrais transmettre les paramètres et les emplacements et à l'ordre dans lequel exécuter les scripts à.

Après avoir exécuté chaque script, je voudrais renvoyer des résultats sur le thread de l'interface utilisateur afin qu'il met à jour la fenêtre de sortie, puis je voudrais que le travailleur passe à la tâche suivante.

Je suis certain que c'est une question fondamentale, mais après avoir examiné weeuueropeworkitem et que je commence essentiellement au travail via un rappel, je ne sais pas comment j'absais ce que j'aurais accompli tiens à accomplir.

Je basse mes hypothèses de cet article Microsoft:

http://msdn.microsoft.com/ EN-US / Bibliothèque / 3DASC8AS (vs.80) .aspx

Merci pour l'info!


1 commentaires

Je jetterais un coup d'oeil à la classe de bus d'arrière-plan. Il est facile de faire fonctionner un processus d'arrière-plan et d'envoyer des mises à jour sur le fil de l'interface utilisateur.


3 Réponses :


-1
votes

1 commentaires

-1: l'interface isynchronizeInvoke IsynchronizeInvoke IsynchronizeVoke n'a pas été reportée dans WPF et n'est pas pris en charge dans ce cadre d'interface utilisateur.



9
votes

WeeuUserSerWorkItem fonctionnerait techniquement, mais est extrêmement bas niveau. Il y a des moyens plus facilement.

Je recommande d'utiliser la nouvelle fonction de tâche de .NET 4.0. Il fait exactement ce que vous voulez, y compris la synchronisation du résultat ou des conditions d'erreur à un autre thread (le fil de l'interface utilisateur, dans ce cas).

Si .NET 4.0 n'est pas une option, je vous recommanderais que Backworker (si votre traitement de fond n'est pas trop complexe) ou des délégués asynchrones tels que Hans mentionnés. Si vous utilisez des délégués ASYNC, utilisez la classe asyncoperation pour prélever les résultats sur le thread de l'interface utilisateur.

L'option est très agréable car elle gère très naturellement les tâches parents / enfants. Backworker ne peut pas être imbriqué. Une autre considération est l'annulation; Tâche et Backworker Ayez un support intégré pour l'annulation, mais pour les délégués ASYNC, vous devez faire le vôtre.

Le seul endroit où tâche est un peu plus complexe que Backworker est en cours de rapport. Ce n'est pas aussi facile que Backworker , mais j'ai un wrapper sur mon blog pour minimiser cela.

résumer, par ordre de préférence:

  1. Tâche - Soutient le maréchalage approprié des erreurs, le concept d'un résultat, d'annulation et de nidification parent / enfant. Son une faiblesse est que le rapport d'avancement n'est pas simple (vous devez créer une autre tâche et la planifier sur le fil de l'interface utilisateur).
  2. Backworker - Soutient le maréchalage approprié des erreurs, le concept d'un résultat, d'annulation et de rapport d'avancement. Sa seule faiblesse est que cela ne supporte pas Nidification parent / enfant, et qui limite son utilisation dans APIS, par exemple, pour une couche d'entreprise.
  3. délégué.beginInvoke avec asyncopération - prend en charge la mise en place correcte des erros, le concept d'un résultat et des rapports d'avancement. Cependant, il n'y a pas de concept intégré d'annulation (bien qu'elle puisse être faite à la main à l'aide d'un volatile bool ). Il ne supporte pas non plus la nidification des parents / enfants.
  4. délégué.begininvoke avec SynchronizationContext - Ceci est identique à l'option (3), sauf qu'il utilise synchronisationContext directement. Le code est légèrement plus complexe, mais le compromis est que la nidification parent / enfant est prise en charge. Toutes les autres limitations sont identiques à l'option (3).
  5. threadpool.QueueUserSerWorkItem avec asyncopération ou synchronisationContext - prend en charge le concept de déclaration d'avancement. L'annulation souffre du même problème que l'option (3). Le maréchalage des erreurs n'est pas facile (en particulier, préservant la trace de la pile). En outre, la nidification parent / enfant n'est possible que si le synchronisationContext est utilisé à la place de asyncopération . En outre, cette option ne prend pas en charge le concept d'un résultat, de sorte que toute valeur de retour doit être transmise en tant qu'arguments.

    Comme vous pouvez le constater, Tâche est le gagnant clair. Il devrait être utilisé à moins que .NET 4.0 n'est pas une option.


3 commentaires

Merci pour la réponse détaillée!


@Stephen Merci pour l'explication et la ventilation élargie. C'est très utile pour comprendre les différentes manières. Au fait, le lien vers votre blog semble être obsolète.


Le Fonctionnalité de nidification parent / enfant n'a pas bien vieilli. Personne n'utilise, et Microsoft souhaite qu'ils puissent revenir dans le temps et l'inventer!



-1
votes

Je sais que c'est une question ancienne, mais je pense que WeeueUserSerWorkItem est utile lorsque vous souhaitez un fil rapide pour le test sans avoir ASYNC / attendre une intoxication qui vient souvent avec la tâche.

Utilisez Dispatcher.Invoke pour obtenir des informations de la File d'attente de message de fenêtre. p>

Exemple de test d'une analyse RFID sans avoir le périphérique réel: P>

        ThreadPool.QueueUserWorkItem(WaitCallback);

        private void WaitCallback(object state)
        {
            while (true)
            {
                string tid = tids[curtid++ % tids.Count()];

                bool orderShowing = Dispatcher.Invoke(() => { return ContentArea.Content == default; });
                if (orderShowing)
                    Dispatcher.Invoke(() => { OnRFIDScan(null, new RFIDArgs { TIDHex = tid }); });
                Thread.Sleep(10000);
            }
        }


0 commentaires