国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

如何讓Task在非線程池線程中執(zhí)行?

這篇具有很好參考價(jià)值的文章主要介紹了如何讓Task在非線程池線程中執(zhí)行?。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

Task承載的操作需要被調(diào)度才能被執(zhí)行,由于.NET默認(rèn)采用基于線程池的調(diào)度器,所以Task默認(rèn)在線程池線程中執(zhí)行。但是有的操作并不適合使用線程池,比如我們?cè)谝粋€(gè)ASP.NET Core應(yīng)用中承載了一些需要長(zhǎng)時(shí)間執(zhí)行的后臺(tái)操作,由于線程池被用來(lái)處理HTTP請(qǐng)求,如果這些后臺(tái)操作也使用線程池來(lái)調(diào)度,就會(huì)造成相互影響。在這種情況下,使用獨(dú)立的一個(gè)或者多個(gè)線程來(lái)執(zhí)行這些后臺(tái)操作可能是一個(gè)更好的選擇。

一、基于線程池的調(diào)度
二、TaskCreationOptions.LongRunning
三、換成異步操作呢?
四、換種寫(xiě)法呢?
五、調(diào)用Wait方法
六、自定義TaskScheduler
七、獨(dú)立線程池

一、基于線程池的調(diào)度

我們通過(guò)如下這個(gè)簡(jiǎn)單的程序來(lái)驗(yàn)證默認(rèn)基于線程池的Task調(diào)度。我們調(diào)用Task類型的靜態(tài)屬性Factory返回一個(gè)TaskFactory對(duì)象,并調(diào)用其StartNew方法啟動(dòng)一個(gè)Task對(duì)象,這個(gè)Task指向的Run方法會(huì)在一個(gè)循環(huán)中調(diào)用Do方法。Do方法使用自旋等待的方式模擬一段耗時(shí)2秒的操作,并在控制臺(tái)輸出當(dāng)前線程的IsThreadPoolThread屬性確定是否是線程池線程。

Task.Factory.StartNew(Run);
Console.Read();

void Run()
{
    while (true)
    {
        Do();
    }
}

void  Do()
{
    var end = DateTime.UtcNow.AddSeconds(2);
    SpinWait.SpinUntil(() => DateTimeOffset.UtcNow > end);
    var isThreadPoolThread = Thread.CurrentThread.IsThreadPoolThread;
    Console.WriteLine($"[{DateTimeOffset.Now}]Is thread pool thread: {isThreadPoolThread}");
}

通過(guò)如下所示的輸出結(jié)果,我們得到了答案:利用TaskFactory創(chuàng)建的Task在默認(rèn)情況下確實(shí)是通過(guò)線程池的形式被調(diào)度的。

如何讓Task在非線程池線程中執(zhí)行?

二、TaskCreationOptions.LongRunning

很明顯,上述Run方法是一個(gè)需要永久執(zhí)行的LongRunning操作,并不適合使用線程池來(lái)執(zhí)行,實(shí)際上TaskFactory在設(shè)計(jì)的時(shí)候就考慮到了這一點(diǎn),我們利用它創(chuàng)建一個(gè)Task的時(shí)候可以指定對(duì)應(yīng)的TaskCreationOptions選項(xiàng),其中一個(gè)選項(xiàng)就是LongRuning。我們通過(guò)如下的方式修改了上面這段程序,在調(diào)用StartNew方法時(shí)指定了這個(gè)選項(xiàng)。

Task.Factory.StartNew(Run, TaskCreationOptions.LongRunning);
Console.Read();

void Run()
{
    while (true)
    {
        Do();
    }
}

void  Do()
{
    var end = DateTime.UtcNow.AddSeconds(2);
    SpinWait.SpinUntil(() => DateTimeOffset.UtcNow > end);
    var isThreadPoolThread = Thread.CurrentThread.IsThreadPoolThread;
    Console.WriteLine($"[{DateTimeOffset.Now}]Is thread pool thread: {isThreadPoolThread}");
}

再次執(zhí)行我們的程序,就會(huì)通過(guò)如下的輸出結(jié)果看到Do方法將不會(huì)在線程池線程中執(zhí)行了。

如何讓Task在非線程池線程中執(zhí)行?

三、換成異步操作呢?

由于LongRunning操作經(jīng)常會(huì)涉及IO操作,所以我們執(zhí)行方法經(jīng)常會(huì)寫(xiě)成異步的形式。如下所示的代碼中,我們將Do方法替換成DoAsync,將2秒的自旋等待替換成Task.Delay。由于DoAsync寫(xiě)成了異步的形式,Run也換成對(duì)應(yīng)的RunAsync。

Task.Factory.StartNew(RunAsync, TaskCreationOptions.LongRunning);
Console.Read();

async Task RunAsync()
{
    while (true)
    {
       await DoAsync();
    }
}

async Task  DoAsync()
{
    await Task.Delay(2000);
    var isThreadPoolThread = Thread.CurrentThread.IsThreadPoolThread;
    Console.WriteLine($"[{DateTimeOffset.Now}]Is thread pool thread: {isThreadPoolThread}");
}

再次啟動(dòng)程序后,我們發(fā)現(xiàn)又切換成了線程池調(diào)度了。為什么會(huì)這樣呢?其實(shí)很好理解,由于原來(lái)返回void的Run方法被替換成了返回Task的RunAsync,傳入StartNew方法表示執(zhí)行操作的委托類型從Action切換成了Func<Task>,雖然我們指定了LongRunning選項(xiàng),但是StartNew方法只是采用這種模式執(zhí)行Func<Task>這個(gè)委托對(duì)象而已,而這個(gè)委托在遇到await的時(shí)候就返回了。至于返回的Task對(duì)象,還是按照默認(rèn)的方式進(jìn)行調(diào)度執(zhí)行。

如何讓Task在非線程池線程中執(zhí)行?

四、換種寫(xiě)法呢?

有人說(shuō),上面我們使用的是一個(gè)方法來(lái)表示作為參數(shù)的委托對(duì)象,如果我們按照如下的方式使用基于async/await的Lambda表達(dá)式呢?實(shí)際上這樣的Lambda表達(dá)式就是Func<Task>的另一種編程方式而已。

Task.Factory.StartNew(async () => { while (true) await DoAsync();}, TaskCreationOptions.LongRunning);
Console.Read();


async Task  DoAsync()
{
    await Task.Delay(2000);
    var isThreadPoolThread = Thread.CurrentThread.IsThreadPoolThread;
    Console.WriteLine($"[{DateTimeOffset.Now}]Is thread pool thread: {isThreadPoolThread}");
}

五、調(diào)用Wait方法

其實(shí)這個(gè)問(wèn)題很好解決,按照如下的方式將DoAsync方法換成同步形式的Do,將基于await的等待替換成針對(duì)Wait方法的調(diào)用就可以了。我想當(dāng)你接觸Task的時(shí)候,就有很多人不斷提醒你,謹(jǐn)慎使用Wait方法,因?yàn)樗鼤?huì)阻塞當(dāng)前線程。實(shí)際上對(duì)于我們的當(dāng)前的應(yīng)用場(chǎng)景,調(diào)用Wait方法才是正確的選擇,因?yàn)槲覀兊某踔跃褪鞘褂靡粋€(gè)獨(dú)立的線程以獨(dú)占的方式來(lái)執(zhí)行后臺(tái)操作。

Task.Factory.StartNew(() => { while (true) Do(); }, TaskCreationOptions.LongRunning);
Console.Read();

void  Do()
{
    Task.Delay(2000).Wait();
    var isThreadPoolThread = Thread.CurrentThread.IsThreadPoolThread;
    Console.WriteLine($"[{DateTimeOffset.Now}]Is thread pool thread: {isThreadPoolThread}");
}

六、自定義TaskScheduler

既然針對(duì)線程池的使用是“Task調(diào)度”導(dǎo)致的,我們自然可以通過(guò)重寫(xiě)TaskScheduler的方式來(lái)解決這個(gè)問(wèn)題。如下這個(gè)自定義的DedicatedThreadTaskScheduler 會(huì)采用獨(dú)立的線程來(lái)執(zhí)行被調(diào)度的Task,線程的數(shù)量可以參數(shù)來(lái)指定。

internal sealed class DedicatedThreadTaskScheduler : TaskScheduler
{
    private readonly BlockingCollection<Task> _tasks = new();
    private readonly Thread[] _threads;
    protected override IEnumerable<Task>? GetScheduledTasks() => _tasks;
    protected override void QueueTask(Task task) => _tasks.Add(task);
    protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) => false;
    public DedicatedThreadTaskScheduler(int threadCount)
    {
        _threads = new Thread[threadCount];
        for (int index = 0; index < threadCount; index++)
        {
            _threads[index] = new Thread(_ =>
            {
                while (true)
                {
                    TryExecuteTask(_tasks.Take());
                }
            });
        }
        Array.ForEach(_threads, it => it.Start());
    }
}

我們演示實(shí)例中Run/Do方法再次還原成如下所示的純異步模式的RunAsync/DoAsync,并在調(diào)用StartNew方法的時(shí)候創(chuàng)建一個(gè)DedicatedThreadTaskScheduler對(duì)象作為最后一個(gè)參數(shù)。

Task.Factory.StartNew(RunAsync, CancellationToken.None, TaskCreationOptions.LongRunning, new DedicatedThreadTaskScheduler(1));
Console.Read();

async Task RunAsync()
{
    while (true)
    {
        await DoAsync();
    }
}

async Task DoAsync()
{
    await Task.Delay(2000);
    var isThreadPoolThread = Thread.CurrentThread.IsThreadPoolThread;
    Console.WriteLine($"[{DateTimeOffset.Now}]Is thread pool thread: {isThreadPoolThread}");
}

由于創(chuàng)建的Task將會(huì)使用指定的DedicatedThreadTaskScheduler 對(duì)象來(lái)調(diào)度,DoAsync方法自然就不會(huì)在線程池線程中執(zhí)行了。

如何讓Task在非線程池線程中執(zhí)行?

七、獨(dú)立線程池

.NET提供的線程池是一個(gè)全局共享的線程池,而我們定義的DedicatedThreadTaskScheduler相當(dāng)于創(chuàng)建了一個(gè)獨(dú)立的線程池,對(duì)象池的效果可以通過(guò)如下這個(gè)簡(jiǎn)單的程序展現(xiàn)出來(lái)。

Task.Factory.StartNew(()=> Task.WhenAll( Enumerable.Range(1,6).Select(it=>DoAsync(it))),
        CancellationToken.None,
        TaskCreationOptions.None,
        new DedicatedThreadTaskScheduler(2));

async Task DoAsync(int index)
{
    await Task.Yield();
    Console.WriteLine($"[{DateTimeOffset.Now.ToString("hh:MM:ss")}]Task {index} is executed in thread {Environment.CurrentManagedThreadId}");
    var endTime = DateTime.UtcNow.AddSeconds(4);
    SpinWait.SpinUntil(() => DateTime.UtcNow > endTime);
    await Task.Delay(1000);
}
Console.ReadLine();

如上面的代碼片段所示,異步方法DoAsync利用自旋等待模擬了一段耗時(shí)4秒的操作,通過(guò)調(diào)用Task.Delay方法模擬了一段耗時(shí)1秒的IO操作。我們?cè)谄渲休敵隽巳蝿?wù)開(kāi)始執(zhí)行的時(shí)間和當(dāng)前線程ID。在調(diào)用的StartNew方法中,我們調(diào)用這個(gè)DoAsync方法創(chuàng)建了6個(gè)Task,這些Task交給創(chuàng)建的DedicatedThreadTaskScheduler進(jìn)行調(diào)度。我們?yōu)檫@個(gè)DedicatedThreadTaskScheduler指定的線程數(shù)量為2。從如下所示的輸出結(jié)果可以看出,6個(gè)操作確實(shí)在兩個(gè)線程中執(zhí)行的。

如何讓Task在非線程池線程中執(zhí)行?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-462940.html

到了這里,關(guān)于如何讓Task在非線程池線程中執(zhí)行?的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 自定義一個(gè)簡(jiǎn)單的Task調(diào)度器、任務(wù)循環(huán)調(diào)度器、TaskScheduler

    自定義一個(gè)簡(jiǎn)單的Task調(diào)度器、任務(wù)循環(huán)調(diào)度器、TaskScheduler

    前言: 自從接觸異步(async await? Task)操作后,始終都不明白,這個(gè)Task調(diào)度的問(wèn)題。 接觸Quartz.net已經(jīng)很久了,只知道它實(shí)現(xiàn)了一套Task調(diào)度的方法,自己跟著Quartz.net源代碼寫(xiě)了遍,調(diào)試后我算是明白了Task調(diào)度的一部分事( ?)。 春風(fēng)來(lái)不遠(yuǎn),只在屋東頭。 ?? 理解Task運(yùn)

    2024年02月05日
    瀏覽(18)
  • QT中的耗時(shí)操作放到子線程中執(zhí)行

    代碼中有sleep的話,如果不放到子線程中執(zhí)行,會(huì)將主線程卡死。 子線程的.h文件 子線程的.cpp文件 調(diào)用的地方的.h文件 調(diào)用的地方的.cpp文件

    2024年02月16日
    瀏覽(17)
  • FreeRTOS如何解決訪問(wèn)沖突/線程不安全(臨界段、互斥鎖、掛起調(diào)度、看門(mén)人任務(wù))

    FreeRTOS如何解決訪問(wèn)沖突/線程不安全(臨界段、互斥鎖、掛起調(diào)度、看門(mén)人任務(wù))

    在多任務(wù)(多線程)系統(tǒng)中,存在一個(gè)隱患,那就是多線程的訪問(wèn)(在FreeRTOS中就是任務(wù))。當(dāng)一個(gè)任務(wù)A開(kāi)始訪問(wèn)一個(gè)資源(外設(shè)、一塊內(nèi)存等),但是A還沒(méi)有完成訪問(wèn),B任務(wù)運(yùn)行了,也開(kāi)始訪問(wèn),這就會(huì)造成數(shù)據(jù)破壞、錯(cuò)誤等問(wèn)題。 例如: 兩個(gè)任務(wù)試圖寫(xiě)入一個(gè)液晶顯示

    2024年02月07日
    瀏覽(988)
  • 【webflux】使用flatMapSequential操作過(guò)濾過(guò)程,不啟動(dòng)新線程執(zhí)行新Flux

    在Spring WebFlux中,可以使用Flux.fromIterable()方法將一個(gè)Iterable轉(zhuǎn)換為Flux對(duì)象,然后使用filter()方法過(guò)濾出符合條件的多個(gè)bean,并且可以使用flatMapSequential()方法將每個(gè)符合條件的bean處理后再進(jìn)行操作。 假設(shè)我們有一個(gè)List對(duì)象,其中每個(gè)Bean對(duì)象都有一個(gè)屬性value,我們需要過(guò)濾出

    2024年02月08日
    瀏覽(21)
  • 【操作系統(tǒng)】聊聊進(jìn)程是如何調(diào)度的

    【操作系統(tǒng)】聊聊進(jìn)程是如何調(diào)度的

    進(jìn)程的引入是為了讓操作系統(tǒng)可以同時(shí)執(zhí)行不同的任務(wù)。而進(jìn)程從創(chuàng)建到銷毀也就對(duì)應(yīng)不同的狀態(tài),進(jìn)程狀態(tài),本質(zhì)上就是為了用有限的計(jì)算機(jī)資源合理且高效地完成更多的任務(wù) 而不同的任務(wù)如何進(jìn)行合理的分配,被CPU執(zhí)行,其實(shí)就是不同的調(diào)度算法。 考慮到不同任務(wù)的耗

    2024年02月09日
    瀏覽(19)
  • pyqt5 如何終止正在執(zhí)行的線程?

    在 PyQt5 中終止正在執(zhí)行的線程,可以通過(guò)一些協(xié)調(diào)的方法來(lái)實(shí)現(xiàn)。一般情況下,直接強(qiáng)行終止線程是不安全的,可能會(huì)導(dǎo)致資源泄漏或者程序異常。相反,我們可以使用一種協(xié)作的方式,通知線程在合適的時(shí)候自行退出。 以下是一種常見(jiàn)的方法,使用標(biāo)志位來(lái)通知線程停止

    2024年02月14日
    瀏覽(26)
  • 如何保證三個(gè)線程按順序執(zhí)行?不會(huì)我教你

    ?????作者:bug菌 ??博客:CSDN、掘金、infoQ、51CTO等 ??簡(jiǎn)介:CSDN|阿里云|華為云|51CTO等社區(qū)博客專家,歷屆博客之星Top30,掘金年度人氣作者Top40,51CTO年度博主Top12,掘金 | InfoQ | 51CTO等社區(qū)優(yōu)質(zhì)創(chuàng)作者,全網(wǎng)粉絲合計(jì) 15w+ ??;硬核微信公眾號(hào)「猿圈奇妙屋」,歡迎你的

    2024年02月07日
    瀏覽(16)
  • JavaSE_day43(多線程單線程區(qū)別,圖解main方法若是單多線程該如何執(zhí)行,如何使用多線程2種方式)

    JavaSE_day43(多線程單線程區(qū)別,圖解main方法若是單多線程該如何執(zhí)行,如何使用多線程2種方式)

    1 A.java ?* 學(xué)習(xí)多線程之前,我們先要了解幾個(gè)關(guān)于多線程有關(guān)的概念。 ?? ? ?? ?A:進(jìn)程:進(jìn)程指正在運(yùn)行的程序。確切的來(lái)說(shuō),當(dāng)一個(gè)程序進(jìn)入內(nèi)存運(yùn)行,即變成一個(gè)進(jìn)程,進(jìn)程是處于運(yùn)行過(guò)程中的程序,并且具有一定獨(dú)立功能。 ?? ? ?? ?B:線程:線程是進(jìn)程中的一個(gè)執(zhí)

    2024年02月08日
    瀏覽(26)
  • 線程池是如何執(zhí)行的?任務(wù)太多會(huì)怎么?

    Java 面試不可能不問(wèn)線程池,無(wú)論是大廠還是小廠。這不,前幾天面試阿里時(shí)也被問(wèn)到了這個(gè)問(wèn)題,雖不難,但這里也系統(tǒng)復(fù)盤(pán)一下。 要搞懂線程池的執(zhí)行流程,最好的方式是去看它的源碼,它的源碼如下: 從上述源碼我們可以看出,當(dāng)任務(wù)來(lái)了之后, 線程池的執(zhí)行流程是

    2024年02月06日
    瀏覽(17)
  • 在Java中如何確保在多線程情況下,所有線程都完成再繼續(xù)執(zhí)行任務(wù)?

    1.使用awaitTermination ????????awaitTermination是executorService自帶的方法,用來(lái)確保所有的線程任務(wù)都執(zhí)行完畢。 例如下使用線程池來(lái)執(zhí)行100個(gè)不同的 SQL 語(yǔ)句,將查詢結(jié)果存儲(chǔ)在一個(gè) List 集合中,具體實(shí)現(xiàn)如下: 定義一個(gè) Runnable 接口的實(shí)現(xiàn)類,用來(lái)執(zhí)行 SQL 查詢?nèi)蝿?wù),該類需要

    2024年02月11日
    瀏覽(20)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包