<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          為什么要小心使用Task.Run

          共 1788字,需瀏覽 4分鐘

           ·

          2020-12-04 08:20

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

          0bf17a02c9b967d73a04c7f1756e182d.webp

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

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

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

          對(duì),應(yīng)該就是它,內(nèi)存泄露,除了這個(gè)原因我再也想不到其它原因了。因?yàn)槲译[約記得多年前我確實(shí)踩過一次這個(gè)坑,也可能是兩次。

          沒錯(cuò),Task.Run?使用不當(dāng),一不留意就會(huì)有內(nèi)存泄露的問題。

          我們先來看一段代碼:

          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?的匿名方法捕獲使用,進(jìn)而導(dǎo)致?MyClass?實(shí)例被引用。當(dāng)外部使用完?MyClass?實(shí)例時(shí),本該由 GC 回收的時(shí)候卻發(fā)現(xiàn)它還被其它資源引用著,所以 GC 認(rèn)為該實(shí)例不應(yīng)用被回收,也就永遠(yuǎn)失去了被回收的機(jī)會(huì)。

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

          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.
          });
          }
          }

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

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

          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.
          });
          }
          }

          也有內(nèi)存泄漏的問題。

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

          -

          精致碼農(nóng)

          帶你洞悉編程與架構(gòu)

          長(zhǎng)按圖片識(shí)別二維碼關(guān)注,不要錯(cuò)過網(wǎng)海相遇的緣分


          瀏覽 67
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  无码人妻一区二区三区三 | 免费黄色视频网站观看 | 不卡在线中文字幕 | 理伦少妇 | 国产HD|