New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Task.Result and Task.Wait design flaw leads to deadlock in high loaded applications #13611
Comments
The workaround if you are blocking threadpool threads is to set threadpool minthreads to a high number; though that isn't very scalable. The main workaround is to not use blocking methods in threadpool threads; and there are alternatives. |
@beannaich,
|
You are basically hobbling the threadpool with
try
and you probably won't have any problems; though its not a good solution |
@benaadams, I set TP to low threads number to show the problem. It will also happen on 200 and 1000 threads but it will just take more time and will require modifying the simulation code for more requests (server may have 50000 ccu, what will you do?). In a real app you will never want to set max threads to such big numbers because it will produce too much threads and make your app very very slow because of context switching thing. Also don't forget that each thread takes 1 MB RAM.
I use NHibernate everywhere in our project and it's blocking. It's impossible to not use. |
https://msdn.microsoft.com/en-us/magazine/jj991977.aspx In short, don't mix async and sync. "Async all the way down." If you can't fit in that model you're kind of stuck. As for the potential of changing this, those would all be BCL concerns, not language concerns. C# doesn't know nor care about |
Raise an issue with NHibernate? A blocking call will block a thread and as you've pointed out the issues with that. |
@HaloFour, when "you can't fit" almost everyone suggests to "just use NHibernate authors already stated that they are not going to support async and that it shouldn't affect performance when compared to app logic. This is an example how "good" people usually understand TP. Do you still think they won't use Anyway NHibernate is a very big project and I don't believe that it can be easily migrated to async. So for my project I will create async wrappers for the most blocking thing in NHibernate - getting connection from pool - which will move blocking calls to a separate custom TP and free the main TP for continuations. I agree, this issue should belong to corefx. |
If NH thinks that DB I/O time is best spent blocking threads then you should seriously find another solution as they are clearly criminally incompetant. If they're the ones recommending to "just use .Result" that further validates my opinion. MS docs very clearly state to not do this, as does every article they've written on the subject. |
If you have to shoot yourself in the foot use
You will have an issue scaling to large numbers of concurrent requests as blocking methods require threads to block - whether you use the threadpool or not; blocking in the threadpool just has other bad side-effects as its a shared resource. |
Roslyn does not appear to be the right repo for this issue. |
Unless you think the problem is in the code generated by the Roslyn compiler, you should close this issue and file a new one against the |
Thanks! |
Run this application:
https://gist.github.com/AqlaSolutions/f8c993bfad32dc9be11703fea4e01422
It simulates network engine receiving requests and calling synchronously
IConnection.OnRequestReceived
. This method calls async method and then synchronously processes the result retrieved withTask.Result
. The async method may take up to 700 ms.During run the simulation will decrease time between requests until deadlock occurs - after that point currently awaiting requests will never be completed.
This example proves that absolutely any call to
Task.Result
orTask.Wait
(before task completion) fromThreadPool
thread will work for some time but will eventually deadlock your application in truly high load scenario. Using these methods fromThreadPool
thread for waiting is always a mistake and should be disallowed (but I understand that it will not happen for compatibility reasons).What do you think? May be some workarounds inside .NET TP? Prioritize continuations over new tasks?
The text was updated successfully, but these errors were encountered: