Is HttpClient truly asynchronous or doing multithreading?

I really doubted to ask this here but couldn't resist the temptation. I might be totally off base here and if I am, please forgive me and ignore this.

When I decompiled the System.Net.Http.dll and looked at the HttpClientHandler's (the default handler for the HttpClient) SendAsync method, I see the following code which I believe is the code that actually makes the network call:

Correct me if I am wrong but Task.Factory.StartNew here picks a thread from the ThreadPool and processes the operation with that thread which basically means that we will be doing multithreading and this is obviously bad for a server application (depending
on the situation of course).

My question is:

Is this the case here or there are some other things that I am missing?

Correct me if I am wrong but Task.Factory.StartNew here picks a thread from the ThreadPool and processes the operation with that thread which basically means that we will be doing multithreading and this is obviously bad for a server application (depending
on the situation of course).

What's inherently wrong with multithreading on the server? Even if the operation were fully async the eventual completion would still happen on a ThreadPool thread.

The primary point is as you've said, don't block the caller in what they thought was a fully async operation. In this situation we know we can't be fully async, so we offload to another thread so they can get on with their business. If they have
no other business then their thread completes and they wait for a callback, net gain zero threads.

Not blocking the caller is most critical on the client side UI thread, but is still important for other types of applications.

I understand the concern now. As you pointed out, we can't be fully async there (I am not sure why but I believe there is a reason), so multithreading is better completely blocking.

What I always know is that when there is an unnecessary thread hop (I understand that the thread hop introduced with HttpClient is not unnecessary comparing completely blocking) for a server application, the performance will be reduced when
I get a lot of traffic (not sure how many is a lot here). I am not saying I am correct here but this is what I know, so that's why I was concerned.

Assume that my ASP.NET application received a request and Thread A started handling it. Then, I made a network call with the HttpClient and at some point
Thread B will pick that up. Also assume that I am handing the async right here and in that case,
Thread A should go back to the ThreadPool till the HttpClient finishes the request. Now, as there are some blocking operations that the HttpWebRequest's BeginGetResponse method is doing, instead of Thread A, the Thread B will be blocked
at some point till operation gets truly async (sorry, magic happens there for me and I don't have a lot info what is actually going on from now on). At that point, the
Thread B will also be freed up till the result comes back. When the result comes back to any thread inside the ThreadPool, it will do whatever it needs registered as callback and hand result off to the
Thread A (assuming we want to get back to the sync context, we should eventually end up with
Thread A).

So, AFAIK, we will be still blocking a thread inside the ThreadPool and we will introduce a thread hop. Is my understanding wrong here?

Also, based on your answer on the MSDN thread that I have linked above, do u guys have any plan on making the entire HTTP request pipeline truly async or will HttpClient always work with HttpWebRequest?

You don't end up back on Thread 1 regardless, though yes your context does get carried over.

Adding HttpClient just adds a Thread 0 to the mix that calls Task.Run as you observed. You'll still end up on Thread 3 eventually.

Cleaning up HTTP is definitely on the TODO list, but it's not clear yet when that will happen. Even then, the biggest changes that would be made would be to take some of the items from BeginGetResponse and make them behave more async, such as proxies
and DNS. This will end up making you switch threads more, not less, but will avoid blocking any threads unnecessarily.