平時還是比較喜歡看書的。。但有時候遇到問題還是經常感到腦袋一蒙。。智商果然是硬傷。。 同事發現了個問題,代碼如下: 在使用HttpClient的GetAsync請求後阻塞查詢.Result“死鎖了”,我們知道GetAsync內部也是一個後臺線程在執行,直到獲取到結果時會調用Task中的SetResu ...
平時還是比較喜歡看書的。。但有時候遇到問題還是經常感到腦袋一蒙。。智商果然是硬傷。。
同事發現了個問題,代碼如下:
class Program { static void Main(string[] args) { HttpClientClass c = new HttpClientClass(); while (true) { Task.Factory.StartNew(() => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId + "開始請求:" + DateTime.Now); c.BeginGetMethod(); }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); System.Threading.Thread.Sleep(10 * 1); } } } public class HttpClientClass { private static readonly HttpClient c; static HttpClientClass() { c = new HttpClient(); c.Timeout = TimeSpan.FromSeconds(15); } public void BeginGetMethod() { try { var r = c.GetAsync("https://www.cnblogs.com/").Result; if (r.IsSuccessStatusCode) Console.WriteLine(Thread.CurrentThread.ManagedThreadId + "ok"); else Console.WriteLine(Thread.CurrentThread.ManagedThreadId + "bad request"); } catch (Exception ex) { Console.WriteLine(ex.GetType().FullName); } }
在使用HttpClient的GetAsync請求後阻塞查詢.Result“死鎖了”,我們知道GetAsync內部也是一個後臺線程在執行,直到獲取到結果時會調用Task中的SetResult方法,然後通過.Result就能回去結果了。。
如果此處有問題,那我們假如做網站開發時,併發請求來了豈不是廢掉了?!!
當然不是這樣。。實際上線程池中處理任務時是存在任務隊列的(不提看源碼的事。。看完就忘。。)此處大概意思就是:主線程創建線程任務時,任務優先順序高於後臺線程創建的線程。這裡的while不停的創建後臺任務就導致了GetAsync方法中的後臺任務一直在等啊等。。所以就發生了所謂的"死鎖"。。其實是根本就沒機會執行。。(沒涉及到線程上下文切換,所以談到這也能發生死鎖時腦袋一蒙。。)
所以可以這麼調用:
Task.Factory.StartNew(() => { while (true) { Task.Factory.StartNew(() => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId + "開始請求:" + DateTime.Now); c.BeginGetMethod(); }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); System.Threading.Thread.Sleep(10 * 1); } });