是否建议与 ContinueWith (来自任务库)一起使用 provTask.Wait() ?

所以最近有人告诉我。用于任务的 ContinueWith 并不是正确的使用方法。我还没有在互联网上找到这方面的证据,所以我会问你们,看看答案是什么。下面是我如何使用。继续:

public Task DoSomething()
{
return Task.Factory.StartNew(() =>
{
Console.WriteLine("Step 1");
})
.ContinueWith((prevTask) =>
{
Console.WriteLine("Step 2");
})
.ContinueWith((prevTask) =>
{
Console.WriteLine("Step 3");
});
}

现在我知道这是一个简单的例子,它会运行得非常快,但是只要假设每个任务执行一些更长的操作。我被告知。ContinueWith,你需要说 preTask。Wait () ; 否则您可以在前一个任务完成之前完成工作。这有可能吗?我假设我的第二和第三个任务只有在他们的前一个任务完成后才会运行。

我被告知如何编写代码:

public Task DoSomething()
{
return Task.Factory.StartNew(() =>
{
Console.WriteLine("Step 1");
})
.ContinueWith((prevTask) =>
{
prevTask.Wait();
Console.WriteLine("Step 2");
})
.ContinueWith((prevTask) =>
{
prevTask.Wait();
Console.WriteLine("Step 3");
});
}
92771 次浏览

You are using it correctly.

Creates a continuation that executes asynchronously when the target Task completes.

Source: Task.ContinueWith Method (Action as MSDN)

Having to call prevTask.Wait() in every Task.ContinueWith invocation seems like a weird way to repeat unnecessary logic - i.e. doing something to be "super duper sure" because you actually don't understand what a certain bit of code does. Like checking for a null just to throw an ArgumentNullException where it would've been thrown anyway.

So, no, whoever told you that is wrong and probably doesn't understand why Task.ContinueWith exists.

From the MSDN on Task.Continuewith

The returned Task will not be scheduled for execution until the current task has completed. If the criteria specified through the continuationOptions parameter are not met, the continuation task will be canceled instead of scheduled.

I think that the way you expect it to work in the first example is the correct way.

Who told you that?

Quoting MSDN:

Creates a continuation that executes asynchronously when the target Task completes.

Also, what would be the purpose of Continue With if it wasn't waiting for the previous task to be completed?

You can even test it by yourself:

Task.Factory.StartNew(() =>
{
Console.WriteLine("Step 1");
Thread.Sleep(2000);
})
.ContinueWith((prevTask) =>
{
Console.WriteLine("I waited step 1 to be completed!");
})
.ContinueWith((prevTask) =>
{
Console.WriteLine("Step 3");
});

Ehhh.... I think some of the current answers are missing something: what happens with exceptions?

The only reason you would call Wait in a continuation would be to observe a potential exception from the antecedent in the continuation itself. The same observation would happen if you accessed Result in the case of a Task<T> and also if you manually accessed the Exception property. Frankly, I wouldn't call Wait or access Result because if there is an exception you'll pay the price of re-raising it which is unnecessary overhead. Instead you can just check the IsFaulted property off the antecedent Task. Alternatively you can create forked workflows by chaining on multiple sibling continuations that only fire based on either success or failure with TaskContinuationOptions.OnlyOnRanToCompletion and TaskContinuationOptions.OnlyOnFaulted.

Now, it's not necessary to observe the exception of the antecedent in the continuation, but you may not want your workflow to move forward if, say, "Step 1" failed. In that case: specifying TaskContinuationOptions.NotOnFaulted to your ContinueWith calls would prevent the continuation logic from ever even firing.

Keep in mind that, if your own continuations don't observe the exception, the person who is waiting on this overall workflow to complete is going to be the one to observe it. Either they're Waiting on the Task upstream or have tacked on their own continuation to know when it is complete. If it is the latter, their continuation would need to use the aforementioned observation logic.

By Accessing Task.Result you are actually doing similar logic to task.wait

You might also want to consider using Task.Run instead of Task.Factory.StartNew.

Stephen Cleary's blog post and the Stephen Toub's post that he references explain the differences. There is also a discussion in this answer.

I will reiterate what many have spoken already, prevTask.Wait() is unnecessary.

For more examples one can go to Chaining Tasks using Continuation Tasks, yet another link by Microsoft with good examples.