簡體   English   中英

在調用 Wait 之前訪問任務上的結果實際上有什么作用?

[英]What does accessing a Result on a Task before calling Wait actually do?

var task = Task.Run(() => DoSomeStuff()).Result;

引擎蓋下會發生什么?

我做了一個小測試:

using System;
using System.Threading.Tasks;

public class Program
{
    public static void Main()
    {
        var r = Task.Run( () => {Thread.Sleep(5000); return 123; }).Result;
        Console.WriteLine(r);
    }
}

5 秒后打印“123”。 那么訪問Task上的任何此類屬性是否可以作為調用Task.Wait()的快捷方式,即這樣做是否安全?


以前我的代碼稱為Task.Delay(5000) ,它立即返回“123”。 我在我的問題中解決了這個問題,但把它留在這里作為評論和答案參考它。

你問了兩個問題。 首先,訪問Result隱式導致同步Wait 是的。 但更重要的問題是:

這樣做安全嗎?

這樣做是不安全的。

很容易陷入這樣一種情況:您正在同步等待的任務在它完成您剛剛進入 sleep的線程之前已安排在將來運行 現在我們有一種情況,在休眠線程完成一些工作之前,線程不會喚醒,因為它處於休眠狀態,所以它永遠不會這樣做

如果您已經知道任務已完成,那么同步等待結果是安全的。 如果不這樣做,那么同步等待是不安全的

現在,您可能會說,假設我通過其他方式知道同步等待未完成的任務是安全的。 那么等待是否安全? 那么,對這個問題的前提,是的,但它仍然可能不聰明的等待。 請記住,異步的全部意義在於在高延遲的世界中有效地管理資源 如果你正在同步等待一個異步任務完成,那么你就是在強迫一個 worker 休眠,直到另一個 worker 完成; 睡覺的工人可能正在工作! 異步的全部意義在於避免工人閑置的情況,所以不要強迫他們這樣做。

await異步等待 這是一個等待,意思是“等待運行當前工作流的其余部分,直到此任務完成后,但在等待時找到一些事情要做”。 我們做了很多工作來將它添加到語言中,所以請使用它!

那么訪問Task上的任何此類屬性是否可以作為調用Task.Wait()的快捷方式?

是的。

文檔

訪問 [ Result ] 屬性的 get 訪問器會阻塞調用線程,直到異步操作完成; 相當於調用了Wait方法。

但是,您的測試並沒有像您認為的那樣做。

Task.Delay(..)返回一個在指定時間后完成的Task 它不會阻塞調用線程。

所以() => { Task.Delay(5000); return 123; } () => { Task.Delay(5000); return 123; } () => { Task.Delay(5000); return 123; }簡單地創建一個新的Task (其將在5秒內完成),然后引發它扔掉並立即返回123

您可以:

  1. 通過執行Task.Delay(5000).Wait() (與Thread.Sleep(5000)做同樣的事情Task.Delay(5000).Wait()阻塞調用線程
  2. 異步等待Task.Delay返回的Task完成: Task.Run(async () => { await Task.Delay(5000); return 123; })

測試不等待Task.Delay()所以它立即返回。 它應該是 :

var r = Task.Run(async  () => { await Task.Delay(5000); return 123; }).Result;

Result的行為是明確定義的——如果任務還沒有完成,它就會阻塞直到它完成。 訪問其他任務屬性不會阻止

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM