2010-09-22 3 views
1

Depuis .NET 4.0, il existe le TPL pour exécuter des tâches asynchrones. Si vous lisez msdn, toutes les opérations asynchrones interagissant avec les formulaires/UI utilisent toujours le modèle InvokeRequire ... Invoke(). Ce que je demande, c'est s'il y a une raison à cela? D'après ce que j'ai appris, TPL devrait être en quelque sorte un remplacement des anciens mécanismes de threading. Alors, quel est le point de l'ignorer quand il s'agit de l'enfilage de l'interface utilisateur? Des pensées à ce sujet?TPL contre InvokeRequired/Invoke

Répondre

4

Cela semble assez subjectif ...

Quand vous dites « Depuis .NET 4.0 », vous dites « en Avril de cette année » - .net a été autour depuis 10 ans, et InvokeRequired/Invoke a été utilisé pour le dernier 9. Pourquoi MS brise-t-elle tout le code UI existant pour une raison quelconque? Même si une nouvelle façon d'appeler un thread existait, ils ne pouvaient pas simplement modifier le motif sans d'énormes problèmes de compatibilité.

En outre, le TPL n'est pas analogue à InvokeRequired/Invoke - le TPL est sur le parallélisme facile, et l'invocation est à propos du code en cours d'exécution sur un thread spécifique . Je ne sais pas pourquoi on remplacerait l'autre même s'il n'y avait pas de problèmes de compatibilité.

Notez qu'il n'y a rien d'arrêt d'utiliser le TPL pour vous assurer d'appeler les composants de l'interface utilisateur sur le thread approprié. En fait, vous pouvez facilement le faire. Mais cela dépend de vous et l'API actuelle ne va pas changer d'une manière qui n'est pas rétrocompatible.

1

Quelle est la question ici? L'existence de TPL ne change pas le fait que les UI sont intrinsèquement mono-thread, et nécessitent l'accès aux contrôles uniquement sur le thread UI. (Et c'est une limitation de Windows, pas une limitation des frameworks d'interface utilisateur .NET TPL ne peut pas changer des décennies de limitations de conception Windows.)

Si votre question concerne le mélange de tâches avec InvokeRequired/Invoke, il y a plus de TPL manière orientée que Invoke. TPL est livré avec un moyen intégré de planifier une tâche de continuation à exécuter sur le thread de l'interface utilisateur. Vous mettez donc votre travail en arrière-plan dans une tâche, puis vos mises à jour de l'interface utilisateur dans une autre tâche. Voir this post on task schedulers and SynchronizationContext.

(Mais vraiment, TPL ne remplace pas les API de fil plus. Si Invoke est la meilleure façon de faire ce que vous essayez de le faire, l'utiliser.)

0
private void WorkProcessingAsync(IWorkItem workItem) 
{ 
    IsBusy = true; 
    /* ============================= 
    * Create a TPL Task and pass the current UiCulture in an state Object to resolve the correct .resx file for translation/globalisation/Multilanguate features in Background Thread 
    * ==============================*/ 
    Task<IWorkItem> task = Task.Factory.StartNew((stateObj) => 
    { 
     // here we are already in the task background thread 
     // save cast the given stateObj 
     var tuple = stateObj as Tuple<IWorkItem, CultureInfo>; 

     Debug.Assert(tuple != null, "tuple != null"); 

     Thread.CurrentThread.CurrentUICulture = tuple.Item2; // Here we set the UI-Thread Culture to the Background Thread 

     var longRunningOperationAnswer = LongRunningOperation.DoLongWork(tuple.Item1); 
     return longRunningOperationAnswer; 

    }, new Tuple<IWorkItem, CultureInfo>(workItem, Thread.CurrentThread.CurrentUICulture)); // here we pass the UI-Thread Culture to the State Object 



    /* ======================================================================= 
    * Handle OnlyOnRanToCompletion Task and process longRunningOperationAnswer back in UiThread 
    * =======================================================================*/ 
    task.ContinueWith((t) => 
    { 
     IsBusy = false; 
     // handle longRunningOperationAnswer here in t.Result 
     Log.Debug("Operation completet with {0}", t.Result); 

    }, CancellationToken.None 
    , TaskContinuationOptions.OnlyOnRanToCompletion 
    , TaskScheduler.FromCurrentSynchronizationContext()); 

    /* ======================================================================= 
    * Handle OnlyOnFaulted Task back in UiThread 
    * =======================================================================*/ 
    task.ContinueWith((t) => 
    { 
     IsBusy = false; 
     AggregateException aggEx = t.Exception; 

     if (aggEx != null) 
     { 
      aggEx.Flatten(); 
      Log.ErrorFormat("The Task exited with Exception(s) \n{0}", aggEx); 
      foreach (Exception ex in aggEx.InnerExceptions) 
      { 
       if (ex is SpecialExaption) 
       { 
        //Handle Ex here 
        return; 
       } 
       if (ex is CustomExeption) 
       { 
        //Handle Ex here 
        return; 
       } 
      } 
     } 
    }, CancellationToken.None 
    , TaskContinuationOptions.OnlyOnFaulted 
    , TaskScheduler.FromCurrentSynchronizationContext()); 
}