精品熟女碰碰人人a久久,多姿,欧美欧美a v日韩中文字幕,日本福利片秋霞国产午夜,欧美成人禁片在线观看

C#?TaskScheduler任務調(diào)度器的實現(xiàn)

c#?taskscheduler任務調(diào)度器的實現(xiàn)

 

什么是taskscheduler?

synchronizationcontext是對“調(diào)度程序(scheduler)”的通用抽象。個別框架會有自己的抽象調(diào)度程序,比如system.threading.tasks。當tasks通過委托的形式進行排隊和執(zhí)行時,會用到system.threading.tasks.taskscheduler。和synchronizationcontext提供了一個virtual post方法用于將委托排隊調(diào)用一樣(稍后,我們會通過典型的委托調(diào)用機制來調(diào)用委托),taskscheduler也提供了一個abstract queuetask方法(稍后,我們會通過executetask方法來調(diào)用該task)。

通過taskscheduler.default我們可以獲取到task默認的調(diào)度程序threadpooltaskscheduler——線程池(譯注:這下知道為什么task默認使用的是線程池線程了吧)。并且可以通過繼承taskscheduler來重寫相關方法來實現(xiàn)在任意時間任意地點進行task調(diào)用。例如,核心庫中有個類,名為system.threading.tasks.concurrentexclusiveschedulerpair,其實例公開了兩個taskscheduler屬性,一個叫exclusivescheduler,另一個叫concurrentscheduler。調(diào)度給concurrentscheduler的任務可以并發(fā),但是要在構造concurrentexclusiveschedulerpair時就要指定最大并發(fā)數(shù)(類似于前面演示的maxconcurrencysynchronizationcontext);相反,在exclusivescheduler執(zhí)行任務時,那么將只允許運行一個排他任務,這個行為很像讀寫鎖。

和synchronizationcontext一樣,taskscheduler也有一個current屬性,會返回當前調(diào)度程序。不過,和synchronizationcontext不同的是,它沒有設置當前調(diào)度程序的方法,而是在啟動task時就要提供,因為當前調(diào)度程序是與當前運行的task相關聯(lián)的。所以,下方的示例程序會輸出“true”,這是因為和startnew一起使用的lambda表達式是在concurrentexclusiveschedulerpair的exclusivescheduler上執(zhí)行的(我們手動指定cesp.exclusivescheduler),并且taskscheduler.current也

using system;
using system.threading.tasks;
class program
{
  static void main()
  {
      var cesp = new concurrentexclusiveschedulerpair();
      task.factory.startnew(() =>
      {
          console.writeline(taskscheduler.current == cesp.exclusivescheduler);
      }, default, taskcreationoptions.none, cesp.exclusivescheduler)
      .wait();
  }
}

 

taskscheduler 任務調(diào)度器的原理

public abstract class taskscheduler
{
  // 任務入口,待調(diào)度執(zhí)行的 task 會通過該方法傳入,調(diào)度器會將任務安排task到指定的隊列(線程池任務隊列(全局任務隊列、本地隊列)、獨立線程、ui線程) 只能被.net framework調(diào)用,不能配派生類調(diào)用
 //
  protected internal abstract void queuetask(task task);
  // 這個是在執(zhí)行 task 回調(diào)的時候才會被執(zhí)行到的方法,放到后面再講
  protected abstract bool tryexecutetaskinline(task task, bool taskwaspreviouslyqueued);
protected abstract bool tryexecutetask(task task, bool taskwaspreviouslyqueued);
// 獲取所有調(diào)度到該 taskscheduler 的 task
protected abstract ienumerable<task>? getscheduledtasks();
}

 

.net中的任務調(diào)度器有哪些

線程池任務調(diào)度器:threadpooltaskscheduler、
核心庫任務調(diào)度器:concurrentexclusiveschedulerpair
ui任務調(diào)度器:synchronizationcontexttaskscheduler,并發(fā)度為1

平時我們在用多線程開發(fā)的時候少不了task,確實task給我們帶來了巨大的編程效率,在task底層有一個taskscheduler,它決定了task該如何被調(diào)度,而在.net framework中有兩種系統(tǒng)定義scheduler,第一個是task默認的threadpooltaskscheduler,還是一種就是synchronizationcontexttaskscheduler(wpf),默認的調(diào)度器無法控制任務優(yōu)先級,那么需要自定義調(diào)度器實現(xiàn)優(yōu)先級控制。以及這兩種類型之外的如何自定義,這篇剛好和大家分享一下。

一:threadpooltaskscheduler

這種scheduler機制是task的默認機制,而且從名字上也可以看到它是一種委托到threadpool的機制,剛好也從側(cè)面說明task是基于threadpool基礎上的封裝,源代碼

threadpooltaskscheduler的原理:將指定的長任務開辟一個獨立的線程去執(zhí)行,未指定的長時間運行的任務就用線程池的線程執(zhí)行

internal sealed class threadpooltaskscheduler : taskscheduler
  {
//其他代碼
 protected internal override void queuetask(task task)
      {
          taskcreationoptions options = task.options;
          if (thread.isthreadstartsupported && (options & taskcreationoptions.longrunning) != 0)
          {
              // run longrunning tasks on their own dedicated thread.
              new thread(s_longrunningthreadwork)
              {
                  isbackground = true,
                  name = ".net long running task"
              }.unsafestart(task);
          }
          else
          {
              // normal handling for non-longrunning tasks.
              threadpool.unsafequeueuserworkiteminternal(task, (options & taskcreationoptions.preferfairness) == 0);
          }
      }
//其他代碼
}

二:synchronizationcontexttaskscheduler

使用條件:只有當前程的同步上下文不為null時,該方法才能正常使用。例如在ui線程(wpf、 winform、 asp.net)中,ui線程的同步上下文不為null。控制臺默認的當前線程同步上下文為null,如果給當前線程設置默認的同步上下文synchronizationcontext.setsynchronizationcontext(new synchronizationcontext());就可以正常使用該方法。如果控制臺程序的線程未設置同步上下將引發(fā)【當前的 synchronizationcontext 不能用作 taskscheduler】異常。

默認的同步上下文將方法委托給線程池執(zhí)行。

使用方式:通過taskscheduler.fromcurrentsynchronizationcontext() 調(diào)用synchronizationcontexttaskscheduler。

原理:初始化時候捕獲當前的線程的同步上下文。 將同步上下文封裝入任務調(diào)度器形成新的任務調(diào)度器synchronizationcontexttaskscheduler。重寫該任務調(diào)度器中的queuetask方法,利用同步上下文的post方法將任務送到不同的處理程序,如果是winform的ui線程同步上下文 的post方法(已重寫post方法),就將任務送到ui線程。如果是控制臺線程(默認為null 設置默認同步上下文后可以正常使用。默認同步上下文采用線程池線程)就將任務送入線程池處理。

在winform中的同步上下文:windowsformssynchronizationcontext
在wpf中的同步上下文:dispatchersynchronizationcontext
在控制臺\線程池\new thread 同步上下文:都默認為null。可以給他們設置默認的同步上下文synchronizationcontext。synchronizationcontext.setsynchronizationcontext(new synchronizationcontext());

synchronizationcontext 綜述 | microsoft docs

以下是synchronizationcontexttaskscheduler部分源代碼

internal sealed class synchronizationcontexttaskscheduler : taskscheduler
  {
//初始化時候 ,捕獲當前線程的同步上下文  
internal synchronizationcontexttaskscheduler()
      {
          m_synchronizationcontext = synchronizationcontext.current ??
              // make sure we have a synccontext to work with
              throw new invalidoperationexception(sr.taskscheduler_fromcurrentsynchronizationcontext_nocurrent);
      }
//其他代碼
private readonly synchronizationcontext m_synchronizationcontext;
protected internal override void queuetask(task task)
      {
          m_synchronizationcontext.post(s_postcallback, (object)task);
      }
//其他代碼
///改變post的調(diào)度方法、 調(diào)用者線程執(zhí)行各方面的任務操作
private static readonly sendorpostcallback s_postcallback = static s =>
      {
          debug.assert(s is task);
          ((task)s).executeentry(); //調(diào)用者線程執(zhí)行各方面的任務操作
      };
}

以下是synchronizationcontext部分源代碼

public partial class synchronizationcontext
  {
    //其他代碼
    public virtual void post(sendorpostcallback d, object? state) => threadpool.queueuserworkitem(static s => s.d(s.state), (d, state), preferlocal: false);
   //其他代碼
  }

有了這個基礎我們再來看一下代碼怎么寫,可以看到,下面這段代碼是不阻塞uithread的,完美~~~

private void button1_click(object sender, eventargs e)
       {
           task task = task.factory.startnew(() =>
           {
               //復雜操作,等待10s
               thread.sleep(10000);
           }).continuewith((t) =>
           {
               button1.text = "hello world";
           }, taskscheduler.fromcurrentsynchronizationcontext());
       }

三:自定義taskscheduler

我們知道在現(xiàn)有的.net framework中只有這么兩種taskscheduler,有些同學可能想問,這些scheduler我用起來不爽,我想自定義一下,這個可以嗎?當然!!!如果你想自定義,只要自定義一個類實現(xiàn)一下taskscheduler就可以了,然后你可以將threadpooltaskscheduler簡化一下,即我要求所有的task都需要走thread,杜絕使用theadpool,這樣可以嗎,當然了,不信你看。

namespace consoleapplication1
{
  class program
  {
      static void main(string[] args)
      {
          var task = task.factory.startnew(() =>
          {
              console.writeline("hello world!!!");
          }, new cancellationtoken(), taskcreationoptions.none, new perthreadtaskscheduler());
          console.read();
      }
  }
  /// <summary>
  /// 每個task一個thread
  /// </summary>
  public class perthreadtaskscheduler : taskscheduler
  {
      protected override ienumerable<task> getscheduledtasks()
      {
          return null;
      }
      protected override void queuetask(task task)
      {
          var thread = new thread(() =>
          {
              tryexecutetask(task);
          });
          thread.start();
      }
      protected override bool tryexecutetaskinline(task task, bool taskwaspreviouslyqueued)
      {
          throw new notimplementedexception();
      }
  }
}

創(chuàng)建一個與當前synchronizationcontext關聯(lián)的taskscheduler。源代碼如下:

假設有一個ui app,它有一個按鈕。當點擊按鈕后,會從網(wǎng)上下載一些文本并將其設置為按鈕的內(nèi)容。我們應當只在ui線程中訪問該按鈕,因此當我們成功下載新的文本后,我們需要從擁有按鈕控制權的的線程中將其設置為按鈕的內(nèi)容。如果不這樣做的話,會得到一個這樣的異常:

system.invalidoperationexception: 'the calling thread cannot access this object because a different thread owns it.'

如果我們自己手動實現(xiàn),那么可以使用前面所述的synchronizationcontext將按鈕內(nèi)容的設置傳回原始上下文,例如借助taskscheduler:

用法如下

private static readonly httpclient s_httpclient = new httpclient();
private void downloadbtn_click(object sender, routedeventargs e)
{
  s_httpclient.getstringasync("http://example.com/currenttime").continuewith(downloadtask =>
  {
      downloadbtn.content = downloadtask.result;
  }, taskscheduler.fromcurrentsynchronizationcontext());//捕獲當前ui線程的同步上下文
}

關于c# taskscheduler任務調(diào)度器的實現(xiàn)的文章就介紹至此,更多相關c# taskscheduler任務調(diào)度器內(nèi)容請搜索碩編程以前的文章,希望以后支持碩編程

下一節(jié):c#控制臺程序的開發(fā)與打包為一個exe文件實例詳解

c# 教程

相關文章