【问题标题】:Question about task continuation关于任务继续的问题
【发布时间】:2011-08-31 04:19:17
【问题描述】:

任务1:

public Task SendMail(string email)
 {
  ...
 }

任务2:

public Task<int> SaveToDB(User user)
 {
  ...
 }

我需要做什么:

  1. task1 失败时,应返回“发送失败”信息;
  2. task1 成功后,task2 开始。
  3. 当 task2 失败时,应返回“保存失败”信息。
  4. task2 成功时,应返回“保存成功”信息。

请帮我找到解决办法:

public Task<string> SendAndSave(User user){
var task1 = SendMail(user.Email);
var task1Failed = task1.ContinueWith(t =>   
{
     var e = task1.Exception;
     return "Send Failed";
}, 
TaskContinuationOptions.OnlyOnFaulted | 
TaskContinuationOptions.ExecuteSynchronously);

var task2 = task1.ContinueWith(t =>
{
    var save = SaveToDB(user);
    try
    {
        int result = save.Result;
        return "Save Succeeded"; 
      }
     catch(AggregateException ae)
     {
          return "Save Failed";
      }
      },
      TaskContinuationOptions.NotOnFaulted); 

 return Task.Factory.ContinueWhenAny(new[] {task1Failed, task2}, t => t.Result);
 }

当我运行它时,我收到一个错误。

我将其调用为:

var result = SendAndSave(user).Result;

错误发生在:

public Task<string> SendAndSave(User user)
{
      ...
      return Task.Factory.ContinueWhenAny(new[] {task1Failed, task2}, t => t.Result);   //Here: A task was cancelled
 }

调试之后,我有两个问题:

  • Q1:task1、task1Failed、task2创建后,每个的值 CreationOption 属性为“无”,尽管其状态为 “等待激活”。似乎所有的延续选项都是 无效。

  • Q2:对于Task.Factory.ContinueWhenAny(new[] {task1Failed, task2}, t => t.Result),我们将其命名为“factoryTask”,即 ContinueWhenAny 似乎无效。在内部设置断点后 task1Failed、task2 和 factoryTask 中的每一个,我偶尔可以看到 factoryTask 中的断点首先被击中,尽管它 应在 task1Failed 或 task2 完成后点击。

有人可以帮忙吗?谢谢。

【问题讨论】:

  • 也许你可以先告诉我们,错误到底是什么?

标签: c# .net multithreading task-parallel-library


【解决方案1】:

虽然我不完全理解你的问题,但我理解这里的问题,基本上你总是会有 task1Failed 或 task2 completes 但不是两者都有,另一个会被取消! 所以在 WaitOnAny 调用中,如果它发现其中一个任务已经被取消,它会崩溃,这实际上取决于任务参数的顺序,所以在你上面的例子中,你首先传递 task1failed,所以如果这个任务完成了 ContinueWhenAny 将起作用很好,因为它检查的第一个任务已经完成,所以它不会检查另一个,但是如果 task1Failed 没有运行所以它处于取消状态,ContinueWhenAny 将抛出!

为避免这种情况,您需要改用 TaskCompletionSource,运行的任务将设置该值,然后在最后返回 tcs.Task.Result

public Task<string> SendAndSave(User user){
var tcs = new TaskCompletionSource<string>();
var task1 = SendMail(user.Email);
var task1Failed = task1.ContinueWith(t =>   
{
     var e = task1.Exception;
     tcs.TrySetResult("Send Failed");
}, 
TaskContinuationOptions.OnlyOnFaulted | 
TaskContinuationOptions.ExecuteSynchronously);

var task2 = task1.ContinueWith(t =>
{
    var save = SaveToDB(user);
    try
    {
        int result = save.Result;
        tcs.TrySetResult("Save Succeeded"); 
    }
    catch(AggregateException ae)
    {
       tcs.TrySetResult("Save Failed"); 
    }
},TaskContinuationOptions.NotOnFaulted); 

 return tcs.Task.Result;
}

【讨论】:

  • 支持你花时间回答这个问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-10
  • 2014-02-04
  • 1970-01-01
  • 2017-06-22
  • 2021-10-24
  • 1970-01-01
相关资源
最近更新 更多