I am using a console application and I have batches of 20 URIs that I need to read from and I have found a massive speed boost by making all tasks and running them in parallel then sorting the results on completion in a different thread (allowing the next batch to be fetched).
In the calls I am currently using, each thread blocks when it gets the response stream, I also see there is a async version of the same method GetResponseAsync
.
I understand there are benefits of freeing up the thread pool by using async Await and Async in same line instead of blocking:
Async version
return Task.Run(async () =>
{
var uri = item.Links.Alternate();
var request = (HttpWebRequest)WebRequest.Create(uri);
var response = await request.GetResponseAsync();
var stream = response.GetResponseStream();
if (stream == null) return null;
var reader = new StreamReader(stream);
return new FetchItemTaskResult(reader.ReadToEnd(), index, uri);
});
Blocking version
return Task<FetchItemTaskResult>.Factory.StartNew(() =>
{
var uri = item.Links.Alternate();
var request = (HttpWebRequest)WebRequest.Create(uri);
var response = request.GetResponse();
var stream = response.GetResponseStream();
if (stream == null) return null;
var reader = new StreamReader(stream);
return new FetchItemTaskResult(reader.ReadToEnd(), index, uri);
});
However I am seeing strange pauses on the console app with the async version where a System.Timers.Timer elapsed event stops being called for a many seconds (when it should go off every second).
The blocking one runs at around 3,500 items per second, CPU usage is at ~30% across all cores.
The async on runs at around 3,800 events per second, CPU usage is a little higher than the blocking but not by much (only 5%)... however my timer I am using seems to pause for around 10 to 15 seconds once every minute or so, in my Main()
function:
private static void Main(string[] args)
{
// snip some code that runs the tasks
var timer = new System.Timers.Timer(1000);
timer.Elapsed += (source, e) =>
{
Console.WriteLine(DateTime.UtcNow);
// snip non relevant code
Console.WriteLine("Commands processed: " + commandsProcessed.Sum(s => s.Value) + " (" + logger.CommandsPerSecond() + " per second)");
};
timer.Start();
Console.ReadKey();
}
So would seem the timer and thread pool are some how related when using async (and only async, no pauses when blocking), or perhaps not, either way any ideas what is going on please and how to diagnose further?