TPL vs. InvokeRequired / Invoke - PullRequest
       13

TPL vs. InvokeRequired / Invoke

1 голос
/ 22 сентября 2010

Начиная с .NET 4.0 существует TPL для выполнения асинхронных задач.Если вы читаете msdn, все асинхронные операции, взаимодействующие с формами / пользовательским интерфейсом, все еще используют шаблон InvokeRequire ... Invoke ().Я спрашиваю, есть ли для этого причина?Из того, что я узнал, TPL должен быть своего рода заменой старых механизмов потоков.Так какой смысл игнорировать это, когда речь идет о потоке пользовательского интерфейса?Есть мысли по этому поводу?

Ответы [ 4 ]

4 голосов
/ 22 сентября 2010

Это кажется довольно субъективным ...

Когда вы говорите «Начиная с .NET 4.0», вы говорите «по состоянию на апрель этого года» - .net существует уже 10 лет, и InvokeRequired/ Invoke использовался в течение последних 9. Почему MS по какой-либо причине нарушает весь существующий код пользовательского интерфейса?Даже если бы существовал новый способ вызова потока, они не могли бы просто изменить шаблон без огромных проблем совместимости.

Кроме того, TPL не аналогичен InvokeRequired / Invoke - TPL о простом параллелизме, иinvoke - это выполнение кода в потоке * .Я не уверен, почему одно заменило бы другое, даже если бы не было проблем с совместимостью.

Обратите внимание, что ничто не мешает вам использовать TPL, чтобы обеспечить вызов компонентов пользовательского интерфейса направильная тема.На самом деле, вы можете легко это сделать.Но это зависит от вас, и текущий API не изменится так, чтобы он не был обратно совместим.

1 голос
/ 22 сентября 2010

Какой вопрос здесь? Существование TPL не меняет того факта, что пользовательские интерфейсы являются однопоточными и требуют доступа к элементам управления только в потоке пользовательского интерфейса. (И это ограничение Windows, а не ограничение .NET UI. TPL не может изменить десятилетние ограничения дизайна Windows.)

Если ваш вопрос касается смешивания задач с InvokeRequired / Invoke, существует более ориентированный на TPL способ, чем Invoke. TPL поставляется со встроенным способом планирования задачи продолжения для выполнения в потоке пользовательского интерфейса. Таким образом, вы помещаете свою фоновую работу в одну задачу, а затем обновляете свой пользовательский интерфейс в другую задачу. См. этот пост о планировщиках задач и SynchronizationContext .

(Но на самом деле TPL не заменяет ни один из более старых API потоков. Если Invoke - лучший способ сделать то, что вы пытаетесь сделать, используйте его.)

1 голос
/ 22 сентября 2010

С помощью TPL вы можете указать целевой поток, используя TaskScheduler.FromCurrentSynchronizationContext этот метод указывает, что задача будет выполняться в главном потоке.Я рекомендую использовать его вместо Invoke.

0 голосов
/ 27 января 2012
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());
}
...