这个方法是异步的吗

本文关键字:异步 方法 | 更新日期: 2023-09-27 18:24:50

此方法使用.Result。这是否意味着任务不会异步运行?是否需要重构才能使每个对令牌的请求真正异步?

public async Task<string> ReturnDataFromUrlAsync(List<List<KeyValuePair<string, string>>> listOfPostData)
{
    string allTokens = "";
    var client = new HttpClient
    {
        BaseAddress = new Uri("http://localhost:23081")
    };
    var downloadTasksQuery = listOfPostData.Select(postData =>
    {
        var content = new FormUrlEncodedContent(postData);
        HttpResponseMessage response = client.PostAsync("/Token", content).Result;                                 
        var responseBodyAsText = response.Content.ReadAsStringAsync();
        return responseBodyAsText;               
    });
    List<Task<string>> downloadTasks = downloadTasksQuery.ToList();   
    while (downloadTasks.Count > 0)
    {
        Task<string> firstFinishedTask = await Task.WhenAny(downloadTasks);
        downloadTasks.Remove(firstFinishedTask);
        // Await the completed task. 
        string content = await firstFinishedTask;
        allTokens = allTokens + content;
    }
    return allTokens;
}

这个方法是异步的吗

所以现在这个调用:

HttpResponseMessage response = client.PostAsync("/Token", content).Result;

将导致调用线程暂停并等待结果。如果将wait关键字放在client.PostAsync之前,它将导致调用线程返回到调用者,并在操作完成后继续。由于这是在linq查询中完成的,您需要使lambda表达式异步,如下所示:

var downloadTasksQuery = listOfPostData.Select(async postData =>
    {
        var content = new FormUrlEncodedContent(postData);
        HttpResponseMessage response = await client.PostAsync("/Token", content);                               
        var responseBodyAsText = await response.Content.ReadAsStringAsync();
        return responseBodyAsText;               
    });

在lambda表达式中追加async关键字将推断返回类型必须为Task类型,并且由于我们也在选择字符串,因此返回类型将为IEnumerable<Task<string>>

我还注意到:

var responseBodyAsText = response.Content.ReadAsStringAsync();

我认为造成混乱的原因是,这条语句实际上返回的是Task,而不是字符串(如果使用var,请小心命名)

再次,我们可以将wait关键字放在response.Content之前,返回关键字将自动推断出来。然后我们可以在linq查询中选择字符串,而不是Task<string>