一次Task.Run異常問題的排查

        最近在測試一個功能代碼時發現一個非常奇怪的問題,主要是Task.Run引起一些不符合邏輯的錯誤,以下針對這一問題排查的總結。

問題代碼

        可以建個控制檯程序來運行以下代碼

    class Program
    {
        static User user = new User();
        static void Main(string[] args)
        {
            for (int i = 0; i < 50; i++)
            {
                Task.Run(user.Init);
            }
            System.Threading.Thread.Sleep(-1);
        }
    }


    public class User
    {


        private bool mInit = false;


        private Task OnInit()
        {
            Console.WriteLine("User init");
            System.Threading.Thread.Sleep(1000);
            return Task.CompletedTask;
        }


        public void Init()
        {
            lock (typeof(User))
            {
                if (!mInit)
                {


                    var task = Task.Run(this.OnInit);
                    if (!task.Wait(5000))
                    {
                        throw new TimeoutException("user init error!");
                    }
                    mInit = true;
                }
            }


        }
    }

以上代碼執行的結果非常奇怪,當在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

如果你想了解某方面的知識或文章可以把想法發送到

[email protected]|[email protected]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章