1

I have a bunch of independent REST calls to make (say 1000) , each call has differing body. How to make these calls in the least amount of time?

I am using a Parallel.foreach loop to to make the calls , but doesn't a call wait for the previous call to finish (on a single thread) , is there any callback kind of system to prevent this and make the process faster?

Parallel.foreach(...){
    (REST call)
    HttpResponseMessage response = this.client.PostAsync(new Uri(url), content).Result;
}

Using await also gives almost same results.

Kitwradr
  • 1,986
  • 3
  • 18
  • 32
  • 1
    Do you need to do something with the results? If so, what? – Tyler Hundley Mar 09 '20 at 06:51
  • Yes I need the results to rank an input(sent in body of REST call) , each REST call will return the score of input with something @TylerHundley – Kitwradr Mar 09 '20 at 06:57
  • Alexei's answer below is how I would do this. Typically `Parallel` is good for CPU bound workloads while `async` is good for IO bound workloads. Keep in mind as others have mentioned that you may still be throttled server side, but for a very basic request to a site with no throttling I was able to make 1000 requests, read the response, and write it to console in ~10 seconds or so. – Tyler Hundley Mar 09 '20 at 07:07

2 Answers2

4

Make all the calls with PostAsync:

var urlAndContentArray = ...

// The fast part
IEnumerable<Task<HttpResponseMessage>> tasks = urlAndContentArray.Select
      (x => this.client.PostAsync(new Uri(x.Url), x.Content));

// IF you care about results: here is the slow part:
var responses = await Task.WhenAll(tasks);

Note that this will make all the calls very quickly as requested, but indeed time it takes to get results is mostly not related to how many requests you send out - it's limited by number of outgoing requests .Net will run in parallel as well as how fast those servers reply (and if they have any DOS protection/throttling).

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • Does this call require high performing systems , say I have 1000 calls can this be made on a PC with 4G RAM? – Kitwradr Mar 09 '20 at 07:00
  • @Kitwradr should be perfectly fine... Just try it. Note that unless you actually configure your app as x64 by default it runs as 32bit and can only use 2Gb anyway... – Alexei Levenkov Mar 09 '20 at 07:03
1

The simplest way to do many async actions in parallel, is to start them without waiting, capture tasks in a collection and then wait untill all tasks will be completed.

For example

var httpClient = new HttpClient();
var payloads = new List<string>(); // this is 1000 payloads

var tasks = payloads.Select(p => httpClient.PostAsync("https://addresss", new StringContent(p)));

await Task.WhenAll(tasks);

It should be enough for start, but mind 2 things.

  1. There is still a connection pool per hostname, what defaults to 4. You can use HttpSocketsHandler to control the pool size.

  2. It will really start or the 1000 items in parallel, what sometimes might be not what you want. To control MAX amount of parallel items you can check ActionBlock