一次Task.Run异常问题的排查
????????最近在測試一個功能代碼時發現一個非常奇怪的問題,主要是Task.Run引起一些不符合邏輯的錯誤,以下針對這一問題排查的總結。
問題代碼
????????可以建個控制臺程序來運行以下代碼
以上代碼執行的結果非常奇怪,當在Debug模式下運行,會拋出超時錯誤。
運行在release模式下則會引起OnIint方法被執行多次,lock完全起不了作用。。
和朋友討論過程中說lock不要和Task.Run混用,但Task.Wait的實現是基于線程信號量的和async/await是有著本質的差異。抱著解決問題的思路把Task.Run直接改成了線程池方式運行,但結果還是一樣。由于找不到問題原因最終去dotnet上提個issues,看一下能提供什么意見。
問題的發現
????????對于一個程序員來說問題沒解決怎能安心呢,隔一天issues沒有響應于是開啟的解決問題的碰撞模式。在throw timeout里打個斷點看一下情況,結果無意中發現Task的狀態是WaitingForActivation
狀態描述是等待內部調度激活,意思是說這代碼并不是不執行或執行有問題,而因為某些狀態導致Task還在等待執行中。然后針對這一問題在網查找了一下才發現這問題的原因,主要問題是for 50已經把線和池中的線程抽光了,然然后在Init方法使用Task.Run的時候就只能等待。。。加上方法后面Task.Wait導致當前線程無法回歸到池,所以就只能引起超時間異常!如果這里的Task.Wait不加上個超時,那這測試代碼就直接處于假死狀態無法繼續工作,一個等待一個試圖獲取線程操作從而形成一個類似于死鎖的問題!
總結
????????當你在使用Task.Run時出現一些非常意想不到的結果時可以通過Task.Status狀態可以更好的定位到問題。Task默認也是基于線程池的,所以在使用Task.Run和Task.Wait的就要注意這一點,雖然可以通過加大線程池的最小數量來解決低并發問題,但高并發下還是會存在線程資源不足的情況;為了確保不出現類似于死鎖的問題,請在使用Task.Wait必須加上超時時間,并且是越短越好,畢竟Wait方法是基于線程阻塞。
BeetleX開源跨平臺通訊框架(支持TLS)
輕松實現高性能:tcp、http、websocket、redis、rpc和網關等服務應用
https://beetlex.io
如果你想了解某方面的知識或文章可以把想法發送到
henryfan@msn.com|admin@beetlex.io
總結
以上是生活随笔為你收集整理的一次Task.Run异常问题的排查的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用 dotnet-monitor 分析
- 下一篇: 在.NET Core 中收集数据的几种方