采用异步。结果方法 [英] Asynchronous method using .Result

查看:158
本文介绍了采用异步。结果方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下方法遍历POSTDATA的列表,以使一个令牌多个请求,例如每个请求使用特定clientID的。我的问题涉及到异步。我试图让令牌(S)的调用是异步。是否使用。结果的必然使该方法同步?

 公共异步任务<串GT; ReturnDataFromUrl1(列表<名单,LT; KeyValuePair<字符串,字符串>>> listOfPostData)
{
   清单<任务<串GT;> Tasklist命令=新的List<任务<串GT;>();
   字符串allTokens =;
   清单<任务<串GT;> downloadTasks =新的List<任务<串GT;>();
   的foreach(在listOfPostData VAR POSTDATA)
   {
       使用(VAR的客户=新的HttpClient())
       {
           client.BaseAddress =新的URI(HTTP://本地主机:23081);           HttpContent httpContent =新FormUrlEn codedContent(POSTDATA);
           HTT presponseMessage响应= client.PostAsync(/令牌,httpContent)。结果;           VAR响应code =(int)的response.Status code;           如果(response.IsSuccessStatus code)
           {
               变种responseBodyAsText = response.Content.ReadAsStringAsync();               taskList.Add(responseBodyAsText);
           }
       }
   }    downloadTasks = taskList.ToList();    而(downloadTasks.Count大于0)
    {
        任务<串GT; firstFinishedTask =等待Task.WhenAny(downloadTasks);        downloadTasks.Remove(firstFinishedTask);        //等待完成的任务。
        字符串内容=等待firstFinishedTask;        allTokens = allTokens +内容;
    }    返回allTokens;
}


解决方案

  

是否使用。结果的必然使该方法同步?


这将使的的一部分块与。结果同步的,因为它同步等待完成的任务(如果你的code不死锁,这是极有可能的环境中使用自定义的的SynchronizationContext )。

这个方法调用:

 任务<串GT; firstFinishedTask =等待Task.WhenAny(downloadTasks);

将是异步作为直到第一流被读出和转换成一个字符串它会产生控制。
如果你已经有了异步标记为的方法,只需等待的那部分,以及:

 的Htt presponseMessage响应=等待client.PostAsync(/令牌,httpContent);

侧面说明:

我想我会采取不同的方法来解决问题。一般情况下,它的网络IO这将消耗时间最长此方法。如果可能的话,并给予没有限制,我会同时使这些网络调用,然后他们来处理结果:

 公共异步任务<串GT; ReturnDataFromUrlAsync(
                                清单<名单,LT; KeyValuePair<字符串,字符串>>> listOfPostData)
{
    VAR的客户=新的HttpClient
    {
        BaseAddress =新的URI(HTTP://本地主机:23081)
    };    VAR downloadTasks = listOfPostData.Select(POSTDATA =>
    {
        VAR内容=新FormUrlEn codedContent(POSTDATA);
        返回client.PostAsync(/令牌,内容);
    })了ToList()。    VAR tokenBuilder =新的StringBuilder(downloadTasks.Count);
    而(downloadTasks.Count大于0)
    {
        VAR finishedTask =等待Task.WhenAny(downloadTasks);
        downloadTasks.Remove(finishedTask);
        VAR响应=等待finishedTask;        如果(!response.IsSuccessStatus code)
            继续;        VAR令牌=等待response.Content.ReadAsStringAsync();
        tokenBuilder.Append(标记);
    }    返回tokenBuilder.ToString();
}

或者因为你需要所有的结果,以便无论如何处理令牌,可以使用 Task.WhenAll 来等待所有的人来完成:

 公共异步任务<串GT; ReturnDataFromUrlAsync(
                                清单<名单,LT; KeyValuePair<字符串,字符串>>> listOfPostData)
{
    VAR的客户=新的HttpClient
    {
        BaseAddress =新的URI(HTTP://本地主机:23081)
    };    VAR downloadTasks = listOfPostData.Select(POSTDATA =>
    {
        VAR内容=新FormUrlEn codedContent(POSTDATA);
        返回client.PostAsync(/令牌,内容);
    });    HTT presponseMessage [] =响应等待Task.WhenAll(downloadTasks);    VAR tokenBuilder =新的StringBuilder(response.Length);
    的foreach(;)message.IsSuccessStatus code在response.Where(消息= GT VAR元素)
    {
        tokenBuilder.Append(等待element.Content.ReadAsStringAsync());
    }
    返回tokenBuilder.ToString();
}

The following method loops through a list of postdata to make multiple requests for a token, for example each request uses a specific clientID. My question relates to async. I'm trying to make the calls for the token(s) to be async. Does the use of .Result necessarily make the method synchronous?

public async Task<string> ReturnDataFromUrl1(List<List<KeyValuePair<string, string>>> listOfPostData)
{        
   List<Task<string>> taskList = new List<Task<string>>();       
   string allTokens = "";
   List<Task<string>> downloadTasks = new List<Task<string>>();


   foreach (var postData in listOfPostData)
   {
       using (var client = new HttpClient())
       {
           client.BaseAddress = new Uri("http://localhost:23081");

           HttpContent httpContent = new FormUrlEncodedContent(postData);
           HttpResponseMessage response = client.PostAsync("/Token", httpContent).Result;

           var responsecode = (int)response.StatusCode;

           if (response.IsSuccessStatusCode)
           {
               var responseBodyAsText = response.Content.ReadAsStringAsync();

               taskList.Add(responseBodyAsText);
           }
       }
   }

    downloadTasks = taskList.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;
}

解决方案

Does the use of .Result necessarily make the method synchronous?

It will make the part which blocks with .Result synchronous, as it synchronously waits for the completion of the Task (If your code doesn't deadlocking, which is highly possible in an environment with a custom SynchronizationContext).

This method invocation:

Task<string> firstFinishedTask = await Task.WhenAny(downloadTasks);

Will be asynchronous as it will yield control until the first stream is read and converted to a string. If you already have a method marked as async, simply await that part as well:

HttpResponseMessage response = await client.PostAsync("/Token", httpContent);

Side Note:

I think I would of taken a different approach to the problem. Generally, it's the network IO which will consume the most time for this method. If possible and given no limitation, I'd concurrently make those network calls, and then process the results as they come:

public async Task<string> ReturnDataFromUrlAsync(
                                List<List<KeyValuePair<string, string>>> listOfPostData)
{
    var client = new HttpClient
    {
        BaseAddress = new Uri("http://localhost:23081")
    };

    var downloadTasks = listOfPostData.Select(postData =>
    {
        var content = new FormUrlEncodedContent(postData);
        return client.PostAsync("/Token", content);
    }).ToList();

    var tokenBuilder = new StringBuilder(downloadTasks.Count);
    while (downloadTasks.Count > 0)
    {
        var finishedTask = await Task.WhenAny(downloadTasks);
        downloadTasks.Remove(finishedTask);
        var response = await finishedTask;

        if (!response.IsSuccessStatusCode)
            continue;

        var token = await response.Content.ReadAsStringAsync();
        tokenBuilder.Append(token);
    }

    return tokenBuilder.ToString();
}

Or since you need all of the results in order to process the the token anyway, you can use Task.WhenAll to wait on all of them to complete:

public async Task<string> ReturnDataFromUrlAsync(
                                List<List<KeyValuePair<string, string>>> listOfPostData)
{
    var client = new HttpClient
    {
        BaseAddress = new Uri("http://localhost:23081")
    };

    var downloadTasks = listOfPostData.Select(postData =>
    {
        var content = new FormUrlEncodedContent(postData);
        return client.PostAsync("/Token", content);
    });

    HttpResponseMessage[] response = await Task.WhenAll(downloadTasks);

    var tokenBuilder = new StringBuilder(response.Length);
    foreach (var element in response.Where(message => message.IsSuccessStatusCode))
    {
        tokenBuilder.Append(await element.Content.ReadAsStringAsync());
    }
    return tokenBuilder.ToString();
}

这篇关于采用异步。结果方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆