{})?這樣寫”,當時沒有想太多,這句話并沒有引起我注意,只顧著回答他“不想在代碼中加?async/awa..." />
    
    

      1. 為什么要小心使用Task.Run

        共 2267字,需瀏覽 5分鐘

         ·

        2020-12-09 00:38


        昨天在博客園有園友問了我一個問題,是這樣的:

        先是半個月前 @碧水青荷 童鞋的一句話“大家都說不要隨便?Task.Run(()=>{})?這樣寫”,當時沒有想太多,這句話并沒有引起我注意,只顧著回答他“不想在代碼中加?async/await?該怎么做”的問題。

        然后這句話被 @褲兜 童鞋注意到,昨天問了我為什么。我當時也很納悶,Task.Run?在并行場景中很常見啊,為什么大家會有不要隨便使用的說法。很遺憾,當時我腦海里認為這種說法只是空穴來風,并沒有細究。

        我有個習慣,就是下班路上在地鐵上快速復盤一下今天發(fā)生的事情。當時這個問題剛好就在腦海里閃現了一下,“為什么大家都說不要隨便使用?Task.Run”。突然想起了多年前的一個晚上……哦,難道是“Ta”?

        對,應該就是它,內存泄露,除了這個原因我再也想不到其它原因了。因為我隱約記得多年前我確實踩過一次這個坑,也可能是兩次。

        沒錯,Task.Run?使用不當,一不留意就會有內存泄露的問題。

        我們先來看一段代碼:

        public?class?MyClass
        {
        private?int _id;
        private Logger _logger;

        public?MyClass(Logger logger)
        {
        _logger = logger;
        }


        public Task Foo(Logger logger)
        {
        return Task.Run(() =>
        {
        _logger.LogInformation($"Executing job with ID {_id}");
        // do sth.
        });
        }
        }

        在這段代碼中,私有成員?_id?被?Task.Run?的匿名方法捕獲使用,進而導致?MyClass?實例被引用。當外部使用完?MyClass?實例時,本該由 GC 回收的時候卻發(fā)現它還被其它資源引用著,所以 GC 認為該實例不應用被回收,也就永遠失去了被回收的機會。

        道理很簡單,我就不再用示例演示了。解決辦法也很簡單,想必很多人都知道,就是使用本地變量。

        public?class?MyClass
        {
        private?int _id;
        private Logger _logger;

        public?MyClass(Logger logger)
        {
        _logger = logger;
        }


        public Task Foo(Logger logger)
        {
        var localId = _id;
        return Task.Run(() =>
        {
        _logger.LogInformation($"Executing job with ID {localId}");
        // do sth.
        });
        }
        }

        通過將值分配給一個本地變量,類就沒有成員被捕獲,即避免了潛在的內存泄漏。

        內存泄漏問題在?Task.Run?身上發(fā)生很常見,容易被大家記住,容易提高警覺。其實不光是?Task.Run,其它地方使用了匿名方法也同樣要小心,比如這個示例:

        public?class?MyClass
        {
        private?int _id;
        private Logger _logger;
        private JobQueue _jobQueue;

        public?MyClass(Logger logger, JobQueue jobQueue)
        {
        _logger = logger;
        _jobQueue = jobQueue;
        }

        public?void?Foo()
        {
        _jobQueue.EnqueueJob(() =>
        {
        _logger.LogInformation($"Executing job with ID {_id}");
        // do sth.
        });
        }
        }

        也有內存泄漏的問題。

        總之,任何使用匿名方法的地方都要避免捕獲類的成員,小心內存泄漏。


        往期精彩回顧




        【推薦】.NET Core開發(fā)實戰(zhàn)視頻課程?★★★

        .NET Core實戰(zhàn)項目之CMS 第一章 入門篇-開篇及總體規(guī)劃

        【.NET Core微服務實戰(zhàn)-統(tǒng)一身份認證】開篇及目錄索引

        Redis基本使用及百億數據量中的使用技巧分享(附視頻地址及觀看指南)

        .NET Core中的一個接口多種實現的依賴注入與動態(tài)選擇看這篇就夠了

        10個小技巧助您寫出高性能的ASP.NET Core代碼

        用abp vNext快速開發(fā)Quartz.NET定時任務管理界面

        在ASP.NET Core中創(chuàng)建基于Quartz.NET托管服務輕松實現作業(yè)調度

        現身說法:實際業(yè)務出發(fā)分析百億數據量下的多表查詢優(yōu)化

        關于C#異步編程你應該了解的幾點建議

        C#異步編程看這篇就夠了


        瀏覽 62
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
          
          

            1. 欧美黄片免费观看 | 成人超碰在线观看 | 快色网站 | 欧美猛少妇色xxxxx免费看 | 国产精品视频麻豆 |