优化从REST API调用获取数据(超过100个)

时间:2014-05-13 10:45:27

标签: c# async-await dotnet-httpclient

我正在尝试从我的服务器进行大量调用到另一台服务器公开的REST API,但代码运行时间太长。

下面是需要花费大量时间的代码。现在我正在使用C#Async/AwaitHTTPClient,我有更好的方法吗?

    static async Task RunAsync()
            {
        HttpClient client = new HttpClient();
                client.BaseAddress = new Uri(URL);

                foreach (var workbk in (workbooksforuserresultingMessage.Items[1] as workbookListType).workbook)
                {

                    if (workbk.project.name == "Ascend")
                    {

                            tsResponse viewresultingMessage = null;
                            //Get View Data 

                            HttpRequestMessage viewrequestMessage = new HttpRequestMessage(HttpMethod.Get, "sites/" + ((siteresultingMessage.Items[0] as siteType).id.ToString()) + "/workbooks/" + workbk.id + "/views");

                            // Add our custom headers
                            viewrequestMessage.Headers.Add("X-Tableau-Auth", (resultingMessage.Items[0] as credentialsType).token.ToString());


                            HttpResponseMessage viewrequestMessageresponse = await client.SendAsync(viewrequestMessage);
                            if (viewrequestMessageresponse.IsSuccessStatusCode)
                            {
                                var viewresponsecontent = await viewrequestMessageresponse.Content.ReadAsStringAsync();

                                XmlSerializer siteserializer = new XmlSerializer(typeof(tsResponse));

                                using (TextReader reader = new StringReader(viewresponsecontent))
                                {
                                   viewresultingMessage = (tsResponse)siteserializer.Deserialize(reader);
                                }
                            }

                    }
                }

                foreach (var workbk in (workbooksforuserresultingMessage.Items[1] as workbookListType).workbook)
                {

                    if (workbk.project.name == "Ascend")
                    {

                        foreach (var vu in workbk.views)
                        {
                            tsResponse viewImageresultingMessage = null;
                            //Get View Data 

                            HttpRequestMessage viewImagerequestMessage = new HttpRequestMessage(HttpMethod.Get, "sites/" + ((siteresultingMessage.Items[0] as siteType).id.ToString()) + "/workbooks/" + workbk.id + "/views/" + vu.id + "/previewImage");

                            // Add our custom headers
                            viewImagerequestMessage.Headers.Add("X-Tableau-Auth", (resultingMessage.Items[0] as credentialsType).token.ToString());


                            HttpResponseMessage viewImagewrequestMessageresponse = await client.SendAsync(viewImagerequestMessage);
                            if (viewImagewrequestMessageresponse.IsSuccessStatusCode)
                            {
                                var viewImageresponsecontent = await viewImagewrequestMessageresponse.Content.ReadAsByteArrayAsync();

                                XmlSerializer siteserializer = new XmlSerializer(typeof(tsResponse));

                                using (var ms = new MemoryStream(viewImageresponsecontent))
                                {
                                    Image returnImage = Image.FromStream(ms);
                                    //return returnImage;
                                }
                            }
                        }
                    }
                }
}

2 个答案:

答案 0 :(得分:0)

等待你的循环中的那些将序列化请求。考虑在任务上使用.ContinueWith来对结果进行一些处理,跟踪数组中的任务,然后在完成所有并行工作后调用Task.WhenAll。

答案 1 :(得分:0)

<@> AS @TheESJ表示等待使您的代码以串行方式执行。也就是说,一旦执行到达第一个await,执行就会有效地“暂停”,并且在Task完成之前不会恢复。您可以通过不等待Task来避免这种情况,只需将其添加到要跟踪的任务列表中即可。

为了方便这一点,我认为如果您引入了几个辅助方法来执行循环体并返回Task,这将有所帮助。

public Task<tsResponse> GetViewString(HttpRequestMessage viewrequestMessage)
   {     
        tsResponse viewresultingMessage = null;

        HttpResponseMessage viewrequestMessageresponse = await client.SendAsync(viewrequestMessage);
        if (viewrequestMessageresponse.IsSuccessStatusCode)
        {
            var viewresponsecontent = await viewrequestMessageresponse.Content.ReadAsStringAsync();

            XmlSerializer siteserializer = new XmlSerializer(typeof(tsResponse));

            using (TextReader reader = new StringReader(viewresponsecontent))
            {
               viewresultingMessage = (tsResponse)siteserializer.Deserialize(reader);
            }
        }

        return viewresultingMessage;
   }

   public Task<tsResponse> GetViewImage(HttpRequestMessage viewImagerequestMessage)
   {     
        tsResponse viewImageresultingMessage = null;
        //Get View Data 

        HttpResponseMessage viewImagewrequestMessageresponse = await client.SendAsync(viewImagerequestMessage);
        if (viewImagewrequestMessageresponse.IsSuccessStatusCode)
        {
            var viewImageresponsecontent = await viewImagewrequestMessageresponse.Content.ReadAsByteArrayAsync();

            XmlSerializer siteserializer = new XmlSerializer(typeof(tsResponse));

            using (var ms = new MemoryStream(viewImageresponsecontent))
            {
                return Image.FromStream(ms);                
            }
        }
   }

然后在主循环中,您只需在方法启动时将任务添加到列表中,这将基本上并行执行任务。如果服务器导致问题,您可能需要增加服务器可以进行的并发连接数。然后你的主要方法就变成了。

 static async Task RunAsync()
  {
      HttpClient client = new HttpClient();
      client.BaseAddress = new Uri(URL);

      var tasks = new List<Task<tsResponse>>();

      foreach (var workbk in (workbooksforuserresultingMessage.Items[1] as workbookListType).workbook)
      {
          if (workbk.project.name == "Ascend")
          {

                  tsResponse viewresultingMessage = null;
                  //Get View Data 

                  HttpRequestMessage viewrequestMessage = new HttpRequestMessage(HttpMethod.Get, "sites/" + ((siteresultingMessage.Items[0] as siteType).id.ToString()) + "/workbooks/" + workbk.id + "/views");

                  // Add our custom headers
                  viewrequestMessage.Headers.Add("X-Tableau-Auth", (resultingMessage.Items[0] as credentialsType).token.ToString());

                 tasks.Add(GetViewString(viewrequestMessage);
          }
      }

      foreach (var workbk in (workbooksforuserresultingMessage.Items[1] as workbookListType).workbook)
      {

          if (workbk.project.name == "Ascend")
          {

              foreach (var vu in workbk.views)
              {
                  tsResponse viewImageresultingMessage = null;
                  //Get View Data 

                  HttpRequestMessage viewImagerequestMessage = new HttpRequestMessage(HttpMethod.Get, "sites/" + ((siteresultingMessage.Items[0] as siteType).id.ToString()) + "/workbooks/" + workbk.id + "/views/" + vu.id + "/previewImage");

                  // Add our custom headers
                  viewImagerequestMessage.Headers.Add("X-Tableau-Auth", (resultingMessage.Items[0] as credentialsType).token.ToString());

                  tasks.Add(GetViewImage(viewImagerequestMessage);
              }
          }
      }

      // wait for all the tasks to complete (non blocking)
      await Task.WhenAll(tasks);
}