欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時(shí)間:2023年05月11日 14:44:43   作者:小林野夫  
本文主要介紹了C#?TaskScheduler任務(wù)調(diào)度器的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧<BR>

什么是TaskScheduler?

SynchronizationContext是對(duì)“調(diào)度程序(scheduler)”的通用抽象。個(gè)別框架會(huì)有自己的抽象調(diào)度程序,比如System.Threading.Tasks。當(dāng)Tasks通過(guò)委托的形式進(jìn)行排隊(duì)和執(zhí)行時(shí),會(huì)用到System.Threading.Tasks.TaskScheduler。和SynchronizationContext提供了一個(gè)virtual Post方法用于將委托排隊(duì)調(diào)用一樣(稍后,我們會(huì)通過(guò)典型的委托調(diào)用機(jī)制來(lái)調(diào)用委托),TaskScheduler也提供了一個(gè)abstract QueueTask方法(稍后,我們會(huì)通過(guò)ExecuteTask方法來(lái)調(diào)用該Task)。

通過(guò)TaskScheduler.Default我們可以獲取到Task默認(rèn)的調(diào)度程序ThreadPoolTaskScheduler——線程池(譯注:這下知道為什么Task默認(rèn)使用的是線程池線程了吧)。并且可以通過(guò)繼承TaskScheduler來(lái)重寫(xiě)相關(guān)方法來(lái)實(shí)現(xiàn)在任意時(shí)間任意地點(diǎn)進(jìn)行Task調(diào)用。例如,核心庫(kù)中有個(gè)類,名為System.Threading.Tasks.ConcurrentExclusiveSchedulerPair,其實(shí)例公開(kāi)了兩個(gè)TaskScheduler屬性,一個(gè)叫ExclusiveScheduler,另一個(gè)叫ConcurrentScheduler。調(diào)度給ConcurrentScheduler的任務(wù)可以并發(fā),但是要在構(gòu)造ConcurrentExclusiveSchedulerPair時(shí)就要指定最大并發(fā)數(shù)(類似于前面演示的MaxConcurrencySynchronizationContext);相反,在ExclusiveScheduler執(zhí)行任務(wù)時(shí),那么將只允許運(yùn)行一個(gè)排他任務(wù),這個(gè)行為很像讀寫(xiě)鎖。

和SynchronizationContext一樣,TaskScheduler也有一個(gè)Current屬性,會(huì)返回當(dāng)前調(diào)度程序。不過(guò),和SynchronizationContext不同的是,它沒(méi)有設(shè)置當(dāng)前調(diào)度程序的方法,而是在啟動(dòng)Task時(shí)就要提供,因?yàn)楫?dāng)前調(diào)度程序是與當(dāng)前運(yùn)行的Task相關(guān)聯(lián)的。所以,下方的示例程序會(huì)輸出“True”,這是因?yàn)楹蚐tartNew一起使用的lambda表達(dá)式是在ConcurrentExclusiveSchedulerPair的ExclusiveScheduler上執(zhí)行的(我們手動(dòng)指定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  任務(wù)調(diào)度器的原理

public abstract class TaskScheduler
{
    // 任務(wù)入口,待調(diào)度執(zhí)行的 Task 會(huì)通過(guò)該方法傳入,調(diào)度器會(huì)將任務(wù)安排task到指定的隊(duì)列(線程池任務(wù)隊(duì)列(全局任務(wù)隊(duì)列、本地隊(duì)列)、獨(dú)立線程、ui線程) 只能被.NET Framework調(diào)用,不能配派生類調(diào)用
   //
    protected internal abstract void QueueTask(Task task);
    // 這個(gè)是在執(zhí)行 Task 回調(diào)的時(shí)候才會(huì)被執(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中的任務(wù)調(diào)度器有哪些

線程池任務(wù)調(diào)度器:ThreadPoolTaskScheduler、
核心庫(kù)任務(wù)調(diào)度器:ConcurrentExclusiveSchedulerPair 
UI任務(wù)調(diào)度器:SynchronizationContextTaskScheduler,并發(fā)度為1

平時(shí)我們?cè)谟枚嗑€程開(kāi)發(fā)的時(shí)候少不了Task,確實(shí)task給我們帶來(lái)了巨大的編程效率,在Task底層有一個(gè)TaskScheduler,它決定了task該如何被調(diào)度,而在.net framework中有兩種系統(tǒng)定義Scheduler,第一個(gè)是Task默認(rèn)的ThreadPoolTaskScheduler,還是一種就是SynchronizationContextTaskScheduler(wpf),默認(rèn)的調(diào)度器無(wú)法控制任務(wù)優(yōu)先級(jí),那么需要自定義調(diào)度器實(shí)現(xiàn)優(yōu)先級(jí)控制。以及這兩種類型之外的如何自定義,這篇?jiǎng)偤煤痛蠹曳窒硪幌隆?/p>

一: ThreadPoolTaskScheduler

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

ThreadPoolTaskScheduler的原理:將指定的長(zhǎng)任務(wù)開(kāi)辟一個(gè)獨(dú)立的線程去執(zhí)行,未指定的長(zhǎng)時(shí)間運(yùn)行的任務(wù)就用線程池的線程執(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

使用條件:只有當(dāng)前程的同步上下文不為null時(shí),該方法才能正常使用。例如在UI線程(wpf、 winform、 asp.net)中,UI線程的同步上下文不為Null??刂婆_(tái)默認(rèn)的當(dāng)前線程同步上下文為null,如果給當(dāng)前線程設(shè)置默認(rèn)的同步上下文SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());就可以正常使用該方法。如果控制臺(tái)程序的線程未設(shè)置同步上下將引發(fā)【當(dāng)前的 SynchronizationContext 不能用作 TaskScheduler】異常。

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

使用方式:通過(guò)TaskScheduler.FromCurrentSynchronizationContext() 調(diào)用SynchronizationContextTaskScheduler。

原理:初始化時(shí)候捕獲當(dāng)前的線程的同步上下文。 將同步上下文封裝入任務(wù)調(diào)度器形成新的任務(wù)調(diào)度器SynchronizationContextTaskScheduler。重寫(xiě)該任務(wù)調(diào)度器中的QueueTask方法,利用同步上下文的post方法將任務(wù)送到不同的處理程序,如果是winform的UI線程同步上下文 的post方法(已重寫(xiě)post方法),就將任務(wù)送到UI線程。如果是控制臺(tái)線程(默認(rèn)為null 設(shè)置默認(rèn)同步上下文后可以正常使用。默認(rèn)同步上下文采用線程池線程)就將任務(wù)送入線程池處理。

在winform中的同步上下文:WindowsFormsSynchronizationContext
在wpf中的同步上下文:DispatcherSynchronizationContext
在控制臺(tái)\線程池\new thread 同步上下文:都默認(rèn)為Null??梢越o他們?cè)O(shè)置默認(rèn)的同步上下文SynchronizationContext。SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());

SynchronizationContext 綜述 | Microsoft Docs

以下是SynchronizationContextTaskScheduler部分源代碼

internal sealed class SynchronizationContextTaskScheduler : TaskScheduler
    {
//初始化時(shí)候 ,捕獲當(dāng)前線程的同步上下文  
 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í)行各方面的任務(wù)操作
  private static readonly SendOrPostCallback s_postCallback = static s =>
        {
            Debug.Assert(s is Task);
            ((Task)s).ExecuteEntry(); //調(diào)用者線程執(zhí)行各方面的任務(wù)操作
        };
 }

以下是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);
   //其他代碼
  }

有了這個(gè)基礎(chǔ)我們?cè)賮?lái)看一下代碼怎么寫(xiě),可以看到,下面這段代碼是不阻塞UIThread的,完美~~~

private void button1_Click(object sender, EventArgs e)
         {
             Task task = Task.Factory.StartNew(() =>
             {
                 //復(fù)雜操作,等待10s
                 Thread.Sleep(10000);
             }).ContinueWith((t) =>
             {
                 button1.Text = "hello world";
             }, TaskScheduler.FromCurrentSynchronizationContext());
         }

三:自定義TaskScheduler

我們知道在現(xiàn)有的.net framework中只有這么兩種TaskScheduler,有些同學(xué)可能想問(wèn),這些Scheduler我用起來(lái)不爽,我想自定義一下,這個(gè)可以嗎?當(dāng)然!??!如果你想自定義,只要自定義一個(gè)類實(shí)現(xiàn)一下TaskScheduler就可以了,然后你可以將ThreadPoolTaskScheduler簡(jiǎn)化一下,即我要求所有的Task都需要走Thread,杜絕使用TheadPool,這樣可以嗎,當(dāng)然了,不信你看。

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>
    /// 每個(gè)Task一個(gè)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)建一個(gè)與當(dāng)前SynchronizationContext關(guān)聯(lián)的TaskScheduler。源代碼如下:

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

System.InvalidOperationException: 'The calling thread cannot access this object because a different thread owns it.'

如果我們自己手動(dòng)實(shí)現(xiàn),那么可以使用前面所述的SynchronizationContext將按鈕內(nèi)容的設(shè)置傳回原始上下文,例如借助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());//捕獲當(dāng)前UI線程的同步上下文
}

到此這篇關(guān)于C# TaskScheduler任務(wù)調(diào)度器的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)C# TaskScheduler任務(wù)調(diào)度器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C#實(shí)現(xiàn)簡(jiǎn)單文本編輯器

    C#實(shí)現(xiàn)簡(jiǎn)單文本編輯器

    這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)簡(jiǎn)單文本編輯器,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-04-04
  • C#生成Word文件(圖片、文字)

    C#生成Word文件(圖片、文字)

    這篇文章主要為大家詳細(xì)介紹了C#生成Word文件,包括圖片、文字等素材,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • WinForm 自動(dòng)完成控件實(shí)例代碼簡(jiǎn)析

    WinForm 自動(dòng)完成控件實(shí)例代碼簡(jiǎn)析

    在Web的應(yīng)用方面有js的插件實(shí)現(xiàn)自動(dòng)完成(或叫智能提示)功能,但在WinForm窗體應(yīng)用方面就沒(méi)那么好了,接下來(lái)參考一下這個(gè)實(shí)例,看看有沒(méi)有以外收獲,感興趣的朋友可以了解下啊,希望本文對(duì)你有幫助啊
    2013-01-01
  • c#委托把方法當(dāng)成參數(shù)(實(shí)例講解)

    c#委托把方法當(dāng)成參數(shù)(實(shí)例講解)

    本篇文章主要是對(duì)c#委托把方法當(dāng)成參數(shù)的實(shí)例代碼進(jìn)行了介紹,需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助
    2014-01-01
  • C#使用Task實(shí)現(xiàn)異步方法

    C#使用Task實(shí)現(xiàn)異步方法

    本文主要介紹了C#使用Task實(shí)現(xiàn)異步方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • C#泛型和反射實(shí)例解析

    C#泛型和反射實(shí)例解析

    這篇文章主要介紹了C#泛型和反射實(shí)例解析,對(duì)于C#初學(xué)者理解泛型和反射有很好的幫助借鑒作用,需要的朋友可以參考下
    2014-08-08
  • C#中委托用法實(shí)例分析

    C#中委托用法實(shí)例分析

    這篇文章主要介紹了C#中委托用法,較為詳細(xì)的分析了C#中委托的概念與相關(guān)的使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-05-05
  • Unity3D實(shí)現(xiàn)待機(jī)狀態(tài)圖片循環(huán)淡入淡出

    Unity3D實(shí)現(xiàn)待機(jī)狀態(tài)圖片循環(huán)淡入淡出

    這篇文章主要為大家詳細(xì)介紹了Unity3D實(shí)現(xiàn)待機(jī)狀態(tài)圖片循環(huán)淡入淡出,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • c# 冒泡排序算法(Bubble Sort) 附實(shí)例代碼

    c# 冒泡排序算法(Bubble Sort) 附實(shí)例代碼

    這篇文章主要介紹了c# 冒泡排序算法,需要的朋友可以參考下
    2013-10-10
  • C#實(shí)現(xiàn)將日期格式化為指定格式

    C#實(shí)現(xiàn)將日期格式化為指定格式

    這篇文章主要為大家詳細(xì)介紹了C#如何使用DateTime.Now.ToString方法將日期格式化為指定格式,文中的示例代碼講解詳細(xì),有需要的小伙伴可以參考下
    2024-01-01

最新評(píng)論