【问题标题】:Getting result from Task.Run从 Task.Run 获取结果
【发布时间】:2019-03-13 16:25:19
【问题描述】:

大家好,我正在尝试从 Task.Run 中获得一些结果,但我无法弄清楚如何

我有多种方法希望并行运行并提取结果: 这是其中一种方法

protected override async Task<IList<EducationDTO>> GetEmployeesEducation(int userId)
{
    IList<EducationDTO> userEducation = await EducationService.GetEducationsByUserId(userId);        
    return userEducation.Count > 0 ? userEducation : null;
}

这里所有方法都将并行运行

public async Task<DTOs.EmployeeDTO> GetEmployeeInfo(int userId)
{
    EmployeeDTO employee = new EmployeeDTO();

    Task task = Task.Run(() => {
        Parallel.Invoke(
        async () => { await GetEmployeeLanguages(userId); },
        // ...
    });
    task.Wait();

    /// extract result and process how ???

    return employee;
}

【问题讨论】:

  • 为什么不直接打电话给var result = await EducationService.GetEducationsByUserId(userId);
  • @bash.d 他的GetEmployeesEducation 方法不是异步的。虽然它可能应该是。
  • @ThePerplexedOne 谢谢,没看到。但我认为这样做是有意义的。
  • 嗨,是的,我可以这样做,但我选择不这样做,此时我只想看看不同的方法比较性能等
  • 这种事情的性能可以忽略不计,即使你有几个不必要的电话,你没有。你可以允许async 向上传播。

标签: c# .net asynchronous async-await task-parallel-library


【解决方案1】:

我有多种方法希望并行运行并提取结果

实际上,您希望同时运行它们。 “并行”意味着受 CPU 限制的代码,但您的代码受 I/O 限制。

所以,根本不要使用Parallel;这是错误的工具:

public async Task<DTOs.EmployeeDTO> GetEmployeeInfo(int userId)
{
  EmployeeDTO employee = new EmployeeDTO();

  // Start all tasks
  var languagesTask = GetEmployeeLanguages(userId);
  var educationsTask = GetEmployeesEducation(userId);
  var outExperiencesTask = GetEmployeesOutExperience(userId);
  var ubiExperiencesTask = GetEmployeesUbiExperience(userId);

  // Asynchronously wait for them all to complete
  await Task.WhenAll(languagesTask, educationsTask, outExperiencesTask, ubiExperiencesTask);

  // Retrieve results
  employee.Languages = await languagesTask;
  employee.Educations = await educationsTask;
  employee.OutExperiences = await outExperiencesTask;
  employee.UbiExperiences = await ubiExperiencesTask;

  return employee;
}

【讨论】:

    【解决方案2】:

    创建一个任务并立即等待它是没有用的,所以放弃StartNew

    也不需要先Wait再获取ResultResult隐式等待。而且该方法根本不是异步的,您可以删除async Task&lt;&gt;并直接返回EmployeeDTO...

    【讨论】:

      【解决方案3】:

      这是我的发现

      public async Task<DTOs.EmployeeDTO> GetEmployeeInfo(int userId)
      {
      
          EmployeeDTO employee = new EmployeeDTO();
      
          Task<EmployeeDTO> task = Task.Factory.StartNew(() =>
          {
              Parallel.Invoke(
               () => { employee.Languages = GetEmployeeLanguages(userId).Result; },
               () => { employee.Educations = GetEmployeesEducation(userId).Result; },
               () => { employee.OutExperiences = GetEmployeesOutExperience(userId).Result; },
               () => { employee.UbiExperiences = GetEmployeesUbiExperience(userId).Result; });
      
              return employee;
          });
          task.Wait();
      
          return task.Result;
      
      }
      

      如果您有任何其他建议或更好的方法,请分享。谢谢。

      【讨论】:

      • 查找 Task.WhenAll 并使用它来代替并行调用
      • 当您已经完成所有任务时,为什么还要使用 Parallel.Invoke?只需使用await Task.WhenAll(langTask, eduTask,...);。然后获取每个已完成任务的结果。每次你认为你需要Wait.Result 时,你应该考虑一下你实际上做错了什么
      • 您是在调用数据库还是 Web 服务?在这两种情况下,在一次调用中返回所有相关对象会更快(很多),而不是尝试“并行”加载它们。此类调用通常由网络延迟主导。您将花费 相同 时间,但会在服务器上引起更大的争用,并且可能会查询/加载相同的表行 4 次
      猜你喜欢
      • 2020-06-19
      • 1970-01-01
      • 2013-08-05
      • 2015-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多