So I want to make a lot of DNS queries.
I create (thousands) of Tasks from the Begin/EndGetHostEntry
async pair:
var lookupTask = Task.Factory.FromAsync
( Dns.BeginGetHostEntry,
(Func<IAsyncResult, IPHostEntry>) Dns.EndGetHostEntry,
"google.com",
null
)
then Task.WaitAll
for everything to complete. I'm seeing the number of ThreadPool
threads increase drastically in response to my requests. If I force the ThreadPool
minThreads
to 500, the workload is consumed considerably faster. All of this points to blocking in the Dns
asynchronous implementation.
If I replace Dns
with a managed Dns client, I can consume the same workload with only 1 or 2 threads in the ThreadPool
with cpu virtually idling.
The thing is, the Dns
implementation is absolutely core to many networking APIs (HttpWebRequest
, WebClient
, HttpClient
), and they all seem to be affected by this issue. If I resolve DNS with a 3rd party library, and make HTTP requests using the IP address as the host in the uri, then alter the Host
header to fix the request, I get blistering performance in comparison to anything involving System.Net.Dns
.
What's going on here? Have I missed something or is the System.Net.Dns
implementation really that bad?
System.Net.Dns uses the windows gethostbyname
function for DNS queries and doesn't really have asynchronous functions at all. The BeginGetHostEntry function is basically just a wrapper for a synchronous GetHostEntry invocation on the thread pool.
Last time I had this same problem with slow/synchronous DNS lookups I eventually just used a large ThreadPool to get the job done since not a single built-in windows or .net DNS related function supports proper (parallel) asynchronous execution.