c# - parallel.foreach and httpclient - strange behaviour -


i have piece of code loops on collection , calls httpclient each iteration. api httpclient calls, takes on average 30-40ms execute. calling sequentially, expected outcome, use parallel.foreach, takes longer. looking closely in logs, can see quite few httpclient calls take more 1000ms execute , time drops 30-40ms. looking in api logs, can see barely goes on 100ms. not sure why spike.

the code

using (var client = new httpclient()) {   var content = new stringcontent(parameters, encoding.utf8, "application/json");   var response = client.postasync(url, content);   _log.info(string.format("took {0} ms send post", watch.elapsedmilliseconds));   watch.restart();    var responsestring = response.result.content.readasstringasync();   _log.info(string.format("took {0} ms readstring after post", watch.elapsedmilliseconds)); } 

the parallel call this

    console.writeline("starting parallel...");     parallel.foreach(recipientcollections, recipientcollection =>        {             // lot of processing happens here create relevant content         var secondarycountryrecipientlist = string.join(",",refinedcountryrecipients);         var emailapiparams = new sendemailparametersmodel(countrysubscriberapplicationid,                                         queueitem.sitecoreid, queueitem.version, queueitem.language, countryfeeditem.subject,                                         countryfeeditem.html, countryfeeditem.from, _recipientsformatter.format(secondarycountryrecipientlist));         log.info(string.format("sending email request {0}. recipients {1}",                                        queueitem.sitecoreid, secondarycountryrecipientlist));          var response = _notificationsapi.invoke(emailapiparams);         }); 

thanks

by default .net allows 2 connections per server. change have change value of servicepointmanager.defaultconnectionlimit larger value, eg 20 or 100.

this won't prevent flooding server or consuming memory if make many requests though. better option use actionblock< t> buffer requests , send them in parallel in controlled function, eg:

 servicepointmanager.defaultconnectionlimit =20;   var client = new httpclient();   var blockoptions=new executiondataflowblockoptions{maxdegreeofparallelism=10};   var emailblock=new actionblock<sendemailparametersmodel>(async arameters=>      {          var watch=new stopwatch();          var content = new stringcontent(parameters, encoding.utf8, "application/json");          var response = await client.postasync(url, content);          _log.info(..);          watch.restart();           var responsestring = await response.result.content.readasstringasync();          _log.info(...);  }); 

sending emails doesn't require parallel invocation more:

foreach(var recipientcollection in recipientcollections) {     var secondarycountryrecipientlist = string.join(",",refinedcountryrecipients);     var emailapiparams = new sendemailparametersmodel(countrysubscriberapplicationid, queueitem.sitecoreid, queueitem.version, queueitem.language, countryfeeditem.subject,countryfeeditem.html, countryfeeditem.from, _recipientsformatter.format(secondarycountryrecipientlist));     emailblock.post(emailapiparams);    log.info(...); } emailblock.complete(); await emailblock.completion(); 

httpclient thread-safe allows use same client requests.

the code above buffer requests , execute them 10 @ time. calling complete() tells block complete , stop processing new messages. await emailblock.completion() waits existing messages finish before proceeding


Comments

Popular posts from this blog

sequelize.js - Sequelize group by with association includes id -

android - Robolectric "INTERNET permission is required" -

java - Android raising EPERM (Operation not permitted) when attempting to send UDP packet after network connection -