<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>

          面試八股文:你寫過自定義任務(wù)調(diào)度器嗎?

          共 4029字,需瀏覽 9分鐘

           ·

          2021-05-08 09:16

          最近入職了新公司,嘗試閱讀祖?zhèn)鞔a,記錄并更新最近的編程認(rèn)知。

          思緒由Q1引發(fā),后續(xù)Q2、Q3基于Q1的發(fā)散探究

          Q1. Task.Run、Task.Factory.StartNew 的區(qū)別?

          我們常使用Task.RunTask.Factory.StartNew創(chuàng)建并啟動任務(wù),但是他們的區(qū)別在哪里?在哪種場景下使用前后者?

          官方推薦使用Task.Run方法啟動基于計算的任務(wù), 當(dāng)需要對長時間運(yùn)行、基于計算的任務(wù)做精細(xì)化控制時使用Task.Factory.StartNew。

          Task.Factory提供了自定義選項(xiàng)、自定義調(diào)度器的能力,這也說明了Task.Run是Task.Factory.StartNew的一個特例,Task.Run 只是提供了一個無參、默認(rèn)的任務(wù)創(chuàng)建和調(diào)度方式。

          當(dāng)你在Task.Run傳遞委托

          Task.Run(someAction);

          實(shí)際上等價于

          Task.Factory.StartNew(someAction, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

          一個長時間運(yùn)行的任務(wù),如果使用Task.Run鐵定會使用線程池線程,可能構(gòu)成濫用線程池線程,這個時候最好在獨(dú)立線程中執(zhí)行任務(wù)。

          Q2. 既然說到Task.Run使用線程池線程,線程池線程有哪些特征?為什么有自定義調(diào)度器一說?

          github: TaskScheduler[1] 251行顯示TaskScheduler.Dafult確實(shí)是線程池任務(wù)調(diào)度器。

          線程池[2]線程的特征:
          ① 池中線程都是后臺線程
          ② 線程可重用,一旦線程池中的線程完成任務(wù),將返回到等待線程隊列中, 避免了創(chuàng)建線程的開銷
          ③ 池中預(yù)熱了工作者線程、IO線程

          我啟動一個腳手架項(xiàng)目:默認(rèn)最大工作者線程32767,最大IO線程1000 ; 默認(rèn)最小工作線程數(shù)、最小IO線程數(shù)均為8個

          github: ThreadPoolTaskScheduler[3] 顯示線程池任務(wù)調(diào)度器是這樣調(diào)度任務(wù)的:

          /// <summary>/// Schedules a task to the ThreadPool./// </summary>/// <param name="task">The task to schedule.</param>protected internal override void QueueTask(Task task){     TaskCreationOptions options = task.Options;     if ((options & TaskCreationOptions.LongRunning) != 0)     {          // Run LongRunning tasks on their own dedicated thread.          Thread thread = new Thread(s_longRunningThreadWork);          thread.IsBackground = true; // Keep this thread from blocking process shutdown          thread.Start(task);    }    else    {         // Normal handling for non-LongRunning tasks.        bool preferLocal = ((options & TaskCreationOptions.PreferFairness) == 0);        ThreadPool.UnsafeQueueUserWorkItemInternal(task, preferLocal);    }}

          請注意8-14行若上層使用者將LongRunning任務(wù)應(yīng)用到默認(rèn)的任務(wù)調(diào)度器(也即ThreadPoolTaskScheduler),ThreadPoolTaskScheduler會有一個兜底方案:會將任務(wù)放在獨(dú)立線程上執(zhí)行。

          何時不使用線程池線程

          有幾種應(yīng)用場景,其中適合創(chuàng)建并管理自己的線程,而非使用線程池線程:

          ?需要一個前臺線程。?需要具有特定優(yōu)先級的線程。?擁有會導(dǎo)致線程長時間阻塞的任務(wù)。線程池具有最大線程數(shù),因此大量被阻塞的線程池線程可能會阻止任務(wù)啟動。?需將線程放入單線程單元。所有 ThreadPool 線程均位于多線程單元中。?需具有與線程關(guān)聯(lián)的穩(wěn)定標(biāo)識,或需將一個線程專用于一項(xiàng)任務(wù)。

          Q3. 既然要自定義任務(wù)調(diào)度器,那我們就來倒騰?

          實(shí)現(xiàn)TaskScheduler 抽象類,其中的抓手是“調(diào)度”,也就是 QueueTask、TryExecuteTask 方法,之后你可以自定義數(shù)據(jù)結(jié)構(gòu)和算法, 從數(shù)據(jù)結(jié)構(gòu)中調(diào)度出任務(wù)執(zhí)行。

          給個例子:

          public sealed class CustomTaskScheduler : TaskScheduler, IDisposable    {        private BlockingCollection<Task> tasksCollection = new BlockingCollection<Task>();        private readonly Thread mainThread = null;        public CustomTaskScheduler()        {            mainThread = new Thread(new ThreadStart(Execute));            if (!mainThread.IsAlive)            {                mainThread.Start();            }        }        private void Execute()        {            foreach (var task in tasksCollection.GetConsumingEnumerable())            {                TryExecuteTask(task);            }        }        protected override IEnumerable<Task> GetScheduledTasks()        {            return tasksCollection.ToArray();        }        protected override void QueueTask(Task task)        {            if (task != null)                tasksCollection.Add(task);                   }        protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)        {            return false;        }        private void Dispose(bool disposing)        {            if (!disposing) return;            tasksCollection.CompleteAdding();            tasksCollection.Dispose();        }        public void Dispose()        {            Dispose(true);            GC.SuppressFinalize(this);        }    }

          引用鏈接

          [1] github: TaskScheduler: https://github.com/dotnet/coreclr/blob/master/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskScheduler.cs
          [2] 線程池: https://docs.microsoft.com/en-us/dotnet/standard/threading/the-managed-thread-pool
          [3] github: ThreadPoolTaskScheduler: https://github.com/dotnet/coreclr/blob/master/src/System.Private.CoreLib/shared/System/Threading/Tasks/ThreadPoolTaskScheduler.cs





          更多干貨及最佳實(shí)踐分享
          關(guān)注并星標(biāo)我們

          瀏覽 37
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <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>
                  欧美综合免费 | 久久久香蕉视频 | 中国黄色操逼大片 | 中文字幕在线观看亚洲 | 国产免费AAA |