简体   繁体   English

ICommand Execute()Task.ContinueWith()

[英]ICommand Execute() Task.ContinueWith()

In the Execute() of a class that implements ICommand in a WPF application, I have an external call to a method which returns a Task 在WPF应用程序中实现ICommand的类的Execute()中,我对一个返回Task的方法进行了外部调用

ICommand Class: ICommand类:

public static void Execute(object parameter)
{
    Cancel(arg1, arg2);
}

private static void Cancel(IList<object> arg1, object arg2)
{

    Task<object> cancelTask = service.AmendAsync
    (
        CancelTokenSource.Token, 
        object arg2
    );

    ProcessCancellingResponse(arg1, arg2);
}

private static void ProcessCancellingResponse(IList<object> arg1, Task<object> cancelTask)
{
    cancelTask.ContinueWith
    (
        task =>
        {
            Update(task.Result.Response);
        },
        CancelTokenSource.Token,
        TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.OnlyOnRanToCompletion,
        TaskScheduler.FromCurrentSynchronizationContext()
    );
}

Service Class: 服务类别:

public Task<object> AmendAsync(CancellationToken cancellationToken, object arg1)
{
    return Task<object>.Factory.StartNew
    (
        () =>
        {
            ...
        },
        cancellationToken,
        TaskCreationOptions.None,
        TaskScheduler.Default
    );
}

My questions are 我的问题是

  1. what thread invokes the ICommend Execute() Is it the UI thread? 什么线程调用ICommend Execute()它是UI线程吗?
  2. Will the cancelTask.ContinueWith() wait on the UI thread or on a background thread? cancelTask.ContinueWith()在UI线程或后台线程上等待吗? ie if the Task takes a long time and it is waiting on the UI thread, the UI might freeze. 即如果Task需要很长时间并且它在UI线程上等待,则UI可能会冻结。

According to Domysee comment, I'll be clear here, the Execute is always run in the UI thread, but you can do in the callback whatever you want including run a background thread, 根据Domysee的评论,我会在这里清楚, Execute 总是在UI线程中运行,但你可以在回调中做任何你想做的事情,包括运行后台线程,

About the continuation, if you don't explicit tell him on with thread to continue, it will do its job on TaskScheduler.Current , else, it will continue on which scheduler you defined. 关于延续,如果你没有明确告诉他继续使用线程,它将在TaskScheduler.Current上完成它的工作,否则,它将继续你定义的调度程序。

Anyway consider to use async\\await with\\out capturing to do a continuation 无论如何,考虑使用async\\await和\\ out捕获来进行延续

await Task.Run(() => ).ConfigureAwait(true);

await Task.Run(() => ).ConfigureAwait(false);

Update 更新

According to question update, 根据问题更新,

Execute -> UI thread 执行 - > UI线程

Cancel => UI thread 取消=> UI线程

AmendAsync => background thread AmendAsync =>后台线程

ContinueWith => UI thread (because you write FromCurrentSynchronizationContext ) ContinueWith => UI线程(因为你写了FromCurrentSynchronizationContext

what thread invokes the ICommend Execute() Is it the UI thread? 什么线程调用ICommend Execute()它是UI线程吗?

Yes, it will always be on a UI thread. 是的,它将始终在UI线程上。

Will the cancelTask.ContinueWith() wait on the UI thread or on a background thread? cancelTask​​.ContinueWith()会在UI线程或后台线程上等待吗?

ContinueWith is just a regular method call. ContinueWith只是一个常规的方法调用。 There's no magic. 没有魔力。 So break it down: 所以打破它:

This: 这个:

private static void ProcessCancellingResponse(IList<object> arg1, Task<object> cancelTask)
{
  cancelTask.ContinueWith
  (
    task =>
    {
        Update(task.Result.Response);
    },
    CancelTokenSource.Token,
    TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.OnlyOnRanToCompletion,
    TaskScheduler.FromCurrentSynchronizationContext()
  );
}

is the same as this: 与此相同:

private static void ProcessCancellingResponse(IList<object> arg1, Task<object> cancelTask)
{
  Action<Task> continuation = task => { Update(Task.Result.Response); };
  var token = CancelTokenSource.Token;
  var options = TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.OnlyOnRanToCompletion;
  var scheduler = TaskScheduler.FromCurrentSynchronizationContext();
  cancelTask.ContinueWith(continuation, token, options, scheduler);
}

Since ProcessCancellingResponse is called on a UI thread, then scheduler will be a scheduler that executes its tasks on that UI thread. 由于在UI线程上调用ProcessCancellingResponse ,因此scheduler将是在该UI线程上执行其任务的调度程序。 Thus, continuation will run on that UI thread. 因此, continuation将在该UI线程上运行。


On a side note, I see at least one mistake: AttachedToParent is almost certainly wrong. 另外,我看到至少有一个错误: AttachedToParent几乎肯定是错的。 Promise tasks (asynchronous tasks) should almost never be attached tasks. 承诺任务(异步任务)几乎不应该是附加任务。

The implementations could be much cleaner, too: 实现也可以更清洁:

private static async Task ProcessCancellingResponseAsync(IList<object> arg1, Task<object> cancelTask)
{
  var result = await cancelTask;
  Update(result.Response);
}

public object Amend(CancellationToken cancellationToken, object arg1)
{
  ...
}

private static void Cancel(IList<object> arg1, object arg2)
{
  Task<object> cancelTask = Task.Run(() => service.Amend
  (
    CancelTokenSource.Token, 
    object arg2
  );

  ProcessCancellingResponse(arg1, arg2);
}
  1. ICommand Execute() when called directly from UI runs on Main thread (UI thread). 直接从UI调用的ICommand Execute()在主线程(UI线程)上运行。

  2. It will depend where code is. 它取决于代码的位置。 If it is directly inside the Execute it will run on main thread as well because you are specifying the scheduler to be TaskScheduler.FromCurrentSynchronizationContext() . 如果它直接位于Execute中,它也将在主线程上运行,因为您将调度程序指定为TaskScheduler.FromCurrentSynchronizationContext()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM