【问题标题】:Why Task.WhenAll return null?为什么 Task.WhenAll 返回 null?
【发布时间】:2022-10-13 19:38:10
【问题描述】:

我有两种返回独立数据的方法。我认为并行运行它们是个好主意。 没有任何修改代码看起来像:

private async Task<Entity> MethodAsync()
{
    ...
    var model1 = await client.Method1(Id1, cancellationToken);            
    var model2 = await client.Method2(Id2, cancellationToken);
    ...
}

这些方法按我的预期返回数据。现在,当我更改代码时,所有方法都返回“null”。当我在 Visual Studio 中检查 Task 对象时,有属性 Id = 2356、Status = RanToCompletion、Method = "{null}"、Result = ""。

private async Task<Entity> MethodAsync()
{
     var model1Task = client.Method1(Id1, cancellationToken);
     var model2Task = client.Method2(Id2, cancellationToken);
     var task = Task.WhenAll(new Task[] { model1Task ,model2Task });         
     await task;     //doesn't work
     //task.Wait();  //doesn't work
     //await Task.WhenAll(new Task[] { model1Task , model2Task }); //doesn't work
     //Task.WhenAll(new Task[] { model1Task, model2Task}); //doesn't work
}

客户端方法的代码几乎相同:

public async Task<Model> Method1(Guid Id, CancellationToken cancellationToken)
{
    HttpResponseMessage responseMessage = await client.GetAsync($"customEndPoint");
    ResponseMessageSingle<Model> response = JsonSerializer.Deserialize<ResponseMessageSingle<Model>>(
        await responseMessage.Content.ReadAsStringAsync(cancellationToken),
        new JsonSerializerOptions(JsonSerializerDefaults.Web));

    return response.result;
}       

private class ResponseMessageSingle<T>
{
    public bool success { get; set; }
    public string message { get; set; }
    public T result { get; set; }
}

还有AuthorizeInterceptor(DelegatingHandler):

protected override async Task<HttpResponseMessage> SendAsync(
          HttpRequestMessage request, CancellationToken cancellationToken)
 {
      some logic...
      request.SetBearerToken(TokenResponse.AccessToken);
      HttpResponseMessage response = await base.SendAsync(request, cancellationToken);    
      return await Task.FromResult(response);
 }

【问题讨论】:

  • “不起作用”是什么意思?例外?什么例外?别的东西?最简单的解释是代码不是线程安全的,并行运行时会抛出异常。
  • “不起作用”不是一个充分的错误描述。你得到一个编译错误?还是意外行为(如异常或错误值)?
  • 在您等待Task.WhenAll 之后,您需要从原始任务中获取结果。 var model1 = await model1Task;
  • 我猜“不起作用”等于“抛出 NullReferenceException”?

标签: c# async-await task


【解决方案1】:

Task.WhenAll 在您的情况下不会返回结果,因为您创建了一个 Task 数组,它没有结果。而且由于您的任务返回不同的结果,因此您无法很好地将其放入数组中。

您应该像这样更改代码以获得方法的结果:

private async Task<Entity> MethodAsync()
{
    var model1Task = client.Method1(Id1, cancellationToken);
    var model2Task = client.Method2(Id2, cancellationToken);
    var task = Task.WhenAll(new Task[] { model1Task ,model2Task });         
    await task;
    var result1 = await model1Task;
    var result2 = await model2Task;
    ...
 }

由于这两种方法都将完成,等待它们将立即为您提供结果。

【讨论】:

  • 可能值得注意的是,不返回结果与返回 null 不同,后者是结果。
  • Task.WhenAll 在这里是多余的。只需等待变量中的任务对象模型1任务模型2任务就像您已经在不涉及 Task.WhenAll 的情况下所做的那样...
  • Task.WhenAll 等待两者完成,即使第一个抛出异常。 IMO 它还使代码意图更清晰。
【解决方案2】:

这里不需要Task.WhenAll,因为:

var model1Task = client.Method1(Id1, cancellationToken);
var model2Task = client.Method2(Id2, cancellationToken);

将调用每个 Method1 和 Method2 从而启动它们各自的异步操作。请注意,这里还没有等待任何东西。

现在正在执行 Method1 和 Method2 的异步操作,您可以继续单独等待每个任务:

var model1 = await model1Task;
var model2 = await model2Task;

这两个任务将完成执行一次模型1任务模型2任务已按任何顺序完成。这几乎看起来是你在这里拍摄的,因此任务.WhenAll在您的情况下没有多大用处。这到底意味着:如果没有任务.WhenAll不再,您遇到的任何问题/错误与任务.WhenAll也不再是了。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2022-12-26
  • 2016-12-28
  • 2015-11-25
  • 2015-07-04
  • 2019-09-29
  • 2015-02-25
  • 2015-10-21
  • 2021-08-12
相关资源
最近更新 更多