Reputation: 1054
I'm confused about async IO operations. In this article Stephen Cleary explains that we should not use Task.Run(() => SomeIoMethod())
because truly async operations should use
standard P/Invoke asynchronous I/O system in .NET
http://blog.stephencleary.com/2013/11/there-is-no-thread.html
However, avoid “fake asynchrony” in libraries. Fake asynchrony is when a component has an async-ready API, but it’s implemented by just wrapping the synchronous API within a thread pool thread. That is counterproductive to scalability on ASP.NET. One prominent example of fake asynchrony is Newtonsoft JSON.NET, an otherwise excellent library. It’s best to not call the (fake) asynchronous versions for serializing JSON; just call the synchronous versions instead. A trickier example of fake asynchrony is the BCL file streams. When a file stream is opened, it must be explicitly opened for asynchronous access; otherwise, it will use fake asynchrony, synchronously blocking a thread pool thread on the file reads and writes.
And he advises to use HttpClient but internaly it use Task.Factory.StartNew()
Does this mean that HttpClient
provides not truly async operations?
Upvotes: 5
Views: 647
Reputation: 456947
Does this mean that HttpClient provides not truly async operations?
Sort of. HttpClient
is in an unusual position, since it's primary implementation uses HttpWebRequest
, which is only partially asynchronous.
In particular, the DNS lookup is synchronous, and I think maybe the proxy resolution, too. After that, it's all asynchronous. So, for most scenarios, the DNS is fast (usually cached) and there isn't a proxy, so it acts asynchronously. Unfortunately, there are enough scenarios (particularly from within corporate networks) where the synchronous operations can cause significant lag.
So, when the team was writing HttpClient
, they had three options:
HttpWebRequest
(and friends) allowing for fully-asynchronous operations. Unfortunately, this would have broken a fair amount of code. Due to the way inheritance is used as extension points in these objects, adding asynchronous methods would be backwards-incompatible.HttpWebRequest
equivalent. Unfortunately, this would take a lot of work and they'd lose all the interoperability with existing WebRequest
-related code.In an ideal world (i.e., when we have infinite developer and tester time), I would prefer (2), but I understand why they chose (3).
On a side note, the code you posted shows a dangerous use of StartNew
, which has actually caused problems due to its use of TaskScheduler.Current
. This has been fixed in .NET Core - not sure when the fix will roll back into .NET Framework proper.
Upvotes: 4
Reputation: 28355
No, your assumptions are wrong.
StartNew
isn't equal to the Run
method.HttpClientHandler
, not the HttpClient
, and you didn't examine the this.startRequest
code from this class. The code you're inspecting is a prepare method, which starts a task in new thread pool, and inside call actual code to start an http request.HTTP-connection is created not on the .NET level of abstraction, and I'm sure that inside startRequest
you'LL find some P/Invoke
method, which will do actual work for:
ThreadPool
to process other tasks.Upvotes: 0