Modèle TPL WinForms avec plusieurs tâches et synchronisation de l’interface utilisateur – est-ce correct?

Je suis nouveau dans la bibliothèque TPL (Task-Parallel Library) et je me demande si la procédure suivante est le moyen le plus efficace d’activer une ou plusieurs tâches, d’assembler les résultats et de les afficher dans une grid de données.

  1. Search1 & Search2 parlent à deux bases de données distinctes, mais renvoient les mêmes résultats.
  2. Je désactive les boutons et allume une roulette.
  3. Je déclenche les tâches en utilisant un seul appel de méthode ContinueWhenAll.
  4. J’ai ajouté le planificateur à l’appel ContinueWhenAll pour mettre à jour les boutons de formulaire, la grid de données et désactiver le compteur.

Q: Est-ce que je le fais de la bonne façon? Y a-t-il un meilleur moyen?
Q: Comment puis-je append une vérification d’annulation / d’exception à cela?
Q: Si je devais append des rapports d’avancement, comment pourrais-je le faire?

La raison pour laquelle j’ai choisi cette méthode plutôt qu’un travailleur d’arrière-plan, c’est que je peux activer chaque tâche de la firebase database en parallèle plutôt que de manière séquentielle. En plus de cela, j’ai pensé que cela pourrait être amusant d’utiliser le TPL. Cependant, comme je n’ai pas pu trouver d’exemples concrets de ce que je fais ci-dessous (tâches multiples), j’ai pensé que ce serait bien de le mettre ici pour obtenir réponses, et espérons être un exemple pour les autres.

Je vous remercie!

Code:

// Disable buttons and start the spinner btnSearch.Enabled = btnClear.Enabled = false; searchSpinner.Active = searchSpinner.Visible = true; // Setup scheduler TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext(); // Start the tasks Task.Factory.ContinueWhenAll( // Define the search tasks that return List new [] { Task.Factory.StartNew<List>(Search1), Task.Factory.StartNew<List>(Search2) }, // Process the return results (taskResults) => { // Create a holding list List documents = new List(); // Iterate through the results and add them to the holding list foreach (var item in taskResults) { documents.AddRange(item.Result); } // Assign the document list to the grid grid.DataSource = documents; // Re-enable the search buttons btnSearch.Enabled = btnClear.Enabled = true; // End the spinner searchSpinner.Active = searchSpinner.Visible = false; }, CancellationToken.None, TaskContinuationOptions.None, scheduler ); 

Q: Est-ce que je le fais de la bonne façon? Y a-t-il un meilleur moyen?

Oui, c’est un bon moyen de gérer ce type de situation. Personnellement, j’envisagerais de refactoriser l’activation / désactivation de l’UI en une méthode distincte, mais à part cela, cela semble très raisonnable.

Q: Comment puis-je append une vérification d’annulation / d’exception à cela?

Vous pouvez faire passer un CancellationToken à vos méthodes, et le faire vérifier et lancer si une annulation est demandée.

Vous devez gérer les exceptions dans lesquelles vous récupérez les résultats de taskResults. Cette ligne:

  documents.AddRange(item.Result); 

C’est l’endroit où l’exception sera levée (en tant qu’exception AggregateException ou OperationCanceledException ) si une exception ou une annulation est survenue pendant les opérations.

Q: Si je devais append des rapports d’avancement, comment pourrais-je le faire?

Le moyen le plus simple serait de passer le planificateur dans vos méthodes. Une fois que vous avez fait cela, vous pouvez l’utiliser pour planifier une tâche qui se met à jour sur le thread d’interface utilisateur, par exemple: Task.Factory.StartNew avec le TaskScheduler spécifié.


cependant, étant donné que je n’ai pas pu trouver d’exemples concrets de ce que je fais ci-dessous (tâches multiples)

Just FYI – J’ai des exemples de travail avec plusieurs tâches dans la partie 18 de ma série sur TPL .

Pour de meilleures pratiques, lisez le document Modèle asynchrone basé sur les tâches . Il comprend des recommandations sur le support d’annulation et la notification de progression pour les API basées sur des Task .

Vous bénéficieriez également des mots clés async / await dans le CTP Async. ils simplifient grandement les continuations de tâches.