第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

意外的任務(wù)取消行為

意外的任務(wù)取消行為

C#
哆啦的時光機 2022-11-21 15:46:34
我創(chuàng)建了一個簡單的 .NET Framework 4.7.2 WPF 應(yīng)用程序,其中包含兩個控件 - 一個文本框和一個按鈕。這是我的代碼:private async void StartTest_Click(object sender, RoutedEventArgs e){    Output.Clear();    var cancellationTokenSource = new CancellationTokenSource();    // Fire and forget    Task.Run(async () => {        try        {            await Task.Delay(TimeSpan.FromMinutes(1), cancellationTokenSource.Token);        }        catch (OperationCanceledException)        {            Task.Delay(TimeSpan.FromSeconds(3)).Wait();            Print("Task delay has been cancelled.");        }    });    await Task.Delay(TimeSpan.FromSeconds(1));    await Task.Run(() =>    {        Print("Before cancellation.");        cancellationTokenSource.Cancel();        Print("After cancellation.");    });}private void Print(string message){    var threadId = Thread.CurrentThread.ManagedThreadId;    var time = DateTime.Now.ToString("HH:mm:ss.ffff");    Dispatcher.Invoke(() =>    {        Output.AppendText($"{ time } [{ threadId }] { message }\n");    });}按下按鈕后,我在文本框中StartTest看到以下結(jié)果:Output12:05:54.1508 [7] Before cancellation.12:05:57.2431 [7] Task delay has been cancelled.12:05:57.2440 [7] After cancellation.我的問題是為什么[7] Task delay has been cancelled.在請求令牌取消的同一線程中執(zhí)行?我希望看到的是[7] Before cancellation.然后是[7] After cancellation.然后Task delay has been cancelled.?;蛘咧辽賂ask delay has been cancelled.在另一個線程中執(zhí)行。請注意,如果我cancellationTokenSource.Cancel()從主線程執(zhí)行,那么輸出看起來像預(yù)期的那樣:12:06:59.5583 [1] Before cancellation.12:06:59.5603 [1] After cancellation.12:07:02.5998 [5] Task delay has been cancelled.
查看完整描述

1 回答

?
Qyouu

TA貢獻1786條經(jīng)驗 獲得超11個贊

我的問題是為什么[7] Task delay has been cancelled.在請求令牌取消的同一線程中執(zhí)行?

這是因為用flagawait安排它的任務(wù)延續(xù)ExecuteSynchronously。我也認(rèn)為這種行為令人驚訝,并且最初將其報告為一個錯誤(作為“按設(shè)計”關(guān)閉)。

更具體地說,await捕獲一個上下文,如果該上下文與正在完成任務(wù)的當(dāng)前上下文兼容,則async延續(xù)將直接在完成該任務(wù)的線程上執(zhí)行。

要逐步完成它:

  • 某些線程池線程“7”運行cancellationTokenSource.Cancel()。

  • 這會導(dǎo)致CancellationTokenSource進入取消狀態(tài)并運行其回調(diào)。

  • 其中一個回調(diào)是Task.Delay. 該回調(diào)不是特定于線程的,因此它在線程 7 上執(zhí)行。

  • 這會導(dǎo)致Task返回的 fromTask.Delay被取消。已經(jīng)從一個線程池線程安排了它的awaitcontinuation,線程池線程都被認(rèn)為是相互兼容的,所以asynccontinuation直接在線程7上執(zhí)行。

提醒一下,線程池線程僅在有代碼要運行時使用。當(dāng)您使用awaitto發(fā)送異步代碼時Task.Run,它可以在一個線程上運行第一部分(直到await),然后在另一個線程上運行另一部分(在 之后await)。

因此,由于線程池線程是可互換的,因此線程 7 在;之后繼續(xù)執(zhí)行該async方法并不是“錯誤的”。await這只是一個問題,因為現(xiàn)在 之后的代碼在那個延續(xù)Cancel上被阻塞了。async

請注意,如果我從主線程執(zhí)行 cancellationTokenSource.Cancel() 那么輸出看起來像預(yù)期的那樣

這是因為 UI 上下文被認(rèn)為與線程池上下文不兼容。因此,當(dāng)Task返回的 fromTask.Delay被取消時,await將看到它在 UI 上下文中而不是線程池上下文中,因此它將其繼續(xù)排隊到線程池而不是直接執(zhí)行它。

有趣的是,當(dāng)我替換Task.Delay(TimeSpan.FromMinutes(1), cancellationTokenSource.Token)cancellationTokenSource.Token.ThrowIfCancellationRequested().NET 時,后臺線程一直處于忙碌狀態(tài),并且輸出再次符合預(yù)期

這不是因為線程“忙”。這是因為沒有回調(diào)了。所以觀察方法是輪詢而不是被通知。

該代碼設(shè)置一個計時器(通過Task.Delay),然后將線程返回到線程池。當(dāng)定時器計時結(jié)束后,從線程池中抓取一個線程,檢查取消令牌源是否被取消;如果不是,則設(shè)置另一個計時器并將線程再次返回到線程池。本段的要點是,Task.Run它不僅僅代表“一個線程”;它在執(zhí)行代碼時只有一個線程(即不在 an 中await),并且線程可以在任何await.


除非您混合使用阻塞代碼和異步代碼,否則await使用的一般問題通常不是問題。ExecuteSynchronously在那種情況下,最好的解決方案是將阻塞代碼更改為異步代碼。如果你不能這樣做,那么你需要小心如何繼續(xù)你async在 之后阻塞的方法await。這主要是TaskCompletionSource<T>和的問題CancellationTokenSource。TaskCompletionSource<T>有一個很好的RunContinuationsAsynchronously選項可以覆蓋ExecuteSynchronously標(biāo)志;不幸的是,CancellationTokenSource沒有;你必須使用排隊你Cancel對線程池的調(diào)用Task.Run。

獎勵:為您的隊友準(zhǔn)備的測驗


查看完整回答
反對 回復(fù) 2022-11-21
  • 1 回答
  • 0 關(guān)注
  • 111 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學(xué)習(xí)伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號