2015-06-19 85 views
0

有人可以解釋爲什麼下面的公共異步Task DoStuff()方法仍然可以工作而不返回任何內容嗎?它沒有說無效,所以我認爲返回類型必須是任務.Net任務類 - 請解釋

當我刪除了異步等待來自DoStuff()方法關鍵字,編譯器給我一個「並非所有的代碼路徑返回一個值」錯誤。但是,如果添加async和await關鍵字,則儘管缺少方法簽名中的關鍵字,但似乎並不需要返回類型。我不明白!

什麼是一個任務?微軟解釋得很不好。謝謝。

namespace Async_and_Await_Example 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      AsyncAwaitDemo demo = new AsyncAwaitDemo(); 
      demo.DoStuff(); 

      for (int i = 0; i < 100; i++) 
      { 
       Console.WriteLine("Working on the Main Thread..................."); 
     } 
    } 
} 
public class AsyncAwaitDemo 
{ 
    public async Task DoStuff() 
    { 
     await Task.Run(() => 
     { 
      CountToFifty(); 
     }); 
    } 

    private static async Task<string> CountToFifty() 
    { 
     int counter; 

     for (counter = 0; counter < 51; counter++) 
     { 
      Console.WriteLine("BG thread: " + counter); 
     } 

     return "Counter = " + counter; 
    } 
} 

}

回答

1

爲什麼下面的公共異步Task DoStuff()方法仍然可以工作而不返回任何東西?

因爲編譯器允許它。當您使用async修飾符標記方法時,會創建一個實際返回Task的狀態機。你可以在任何反編譯器中看到它。

當我從DoStuff()方法中刪除異步和等待關鍵字時,編譯器給我一個「並非所有代碼路徑都返回一個值」的錯誤。

因爲不再有一個狀態機創建,它返回一個Task,你必須現在就自己做,因爲沒有更多的編譯器魔術。

究竟是一項任務?

正如其他人所說,只是一個將在未來完成的工作承諾。 A Task可以代表許多事情,其中​​之一是異步操作。這個魔術配上async-await關鍵字。編譯器魔術與Task有特殊關係,但可以等待任何類型的實現GetAwaiter方法。更多關於here

0

這是因爲async/await是魔術。好吧,這不是很神奇,但是async/await編譯器正在重新編寫你的方法,以便它返回Task。就像CountToFifty()返回一個Task<string>但您的方法返回string

A Task本身沒什麼特別的。這只是一個普通的.Net類,用於表示可能尚未完成的操作。

沒有異步/等待編譯器不會修改DoStuff()因此它是你自己返回一個Task對象。

2

一個任務本質上是一個promise (or future)。它「承諾」你開始的異步方法最終會完成任務。使用任務對象以便您可以獲取有關任務完成時間的信息。還有一個任務的generic version,它只是承諾在任務完成時獲得一個值。

一旦啓動異步方法,就會返回一個對象Task。該方法幾乎立即返回,但實際工作可能在稍後完成。然後您可以通過wait完成任務以阻止當前線程,並且只需等到異步方法完成即可。

當你在一個異步執行自己 - 這通常是你想異步調用的時候做什麼樣的方法,那麼你可以等待那些使用任務對象的await關鍵字任務。這基本上暫停了您當前所在的異步方法,並在您等待的任務完成後立即返回執行。

await關鍵字僅在異步方法中可用,由方法說明符async指示。這些方法會自動返回一個任務對象作爲返回值:如果你沒有從異步方法中明確返回任何東西,它會返回一個Task對象;如果從異步方法返回類型爲T的對象,則實際上它會返回一個可等待的Task<T>對象。一旦任務完成,Task<T>類型就可以「解包」。這允許您獲取T類型的實際對象。

最後,async方法也可以不返回任何內容,void,使他們「火和忘記」。如果調用一個異步方法,其返回類型爲void,它將異步執行(「fire」),但由於沒有任務對象需要等待(「忘記」),因此無法知道何時完成。 )。這就是爲什麼你總想避免async void方法的原因(它們對於異常處理也不好),並且總是使用「真正的」等待異步方法(取而代之的是那些返回一些任務對象的方法)。但是您仍然可以使用async void方法啓動異步執行而不會阻止您的主線程。否則,您可以通過調用任務中的Wait()方法來阻止它。

欲瞭解更多信息,請查看以下鏈接:

0

由於異步方法不立即返回。一種方法可能需要查詢外部源。這需要時間 - 而其他代碼可以運行。這是Method中等待異步的目的。因此,當我們使用await關鍵字時,並不總是需要在Async Method中返回。

查看Explanation of Tasks by DotNetPearls瞭解更多信息。

0

正如其他人所指出的,任務是「承諾」或「未來」 - 也就是說,它代表了將來可能完成的一些操作。

Task表示無返回值的操作,Task<T>表示返回值爲T的操作。

注意Task是有益的(而不是void),因爲操作可以完成成功或用一個異常(或取消)和Task能夠表示這些端狀態。

有人可以解釋爲什麼下面的公共異步任務DoStuff()方法仍然可以不返回任何東西?

async關鍵字將構建一個狀態機的方法和狀態機將創建一個Task對象,它表示該方法。如果您的async方法返回值,則狀態機將該返回值放在Task<T>上。如果您的async方法引發異常,則狀態機將該異常置於Task/Task<T>上。

究竟是一項任務?

我描述了Task是在async/await上下文。由於Task在以其他方式使用時具有非常不同的含義,因此出現部分混淆。我使用Promise Task來表示異步任務,委託任務用於代碼運行任務。

async狀態機創建的任務始終爲Promise Tasks。一般來說,異步任務應該是await'ed,而不是Wait'ed。你應該避免async void(因爲狀態機沒有辦法代表方法,它有令人驚訝的異常處理語義)。

您可能會發現我的async intro以及我的article on best practices有幫助。

0

另一種看待這個問題的方法是讓我們假設你有4件事要做,以響應來自客戶的http請求。

  1. 在數據庫中輸入訂單。 Task.Run(PlaceOrder)
  2. 發送給客戶一封感謝電子郵件。 Task.Run(SendEmail)
  3. 發送請求到您的履行中心api。 Task.Run(PlaceOrder)
  4. 記錄會話請求。 Task.Run(LogRequest)

因此,與其說是談論合同,承諾,狀態服務器等,任務就是線程,將工作分散到所有核心/處理器中。我有4個核心和8個處理器。如果我執行上述任務,我可以看到所有8個處理器都在運行,速度提高了一倍以上。這是一項任務。

它變得更好。現在所有8個處理器都在運行,但我們可以更快地完成這項工作。雖然他們在所有8個處理器上運行,但他們輪流或排隊等待對方完成。假設平均每個任務需要5秒鐘,所以我對客戶的響應時間是20秒,但我們只是將其減半。如果我使用異步/等待,我可以同時推送所有4個任務,因此它們都不會彼此等待。所以現在我可以看到所有8個處理器都在運行,但現在他們使用了更多的CPU並完成了它們。

但是等一下,他們仍然很慢,因爲發送訂單的api請求花了8秒鐘,客戶和其他任務必須等待它完成。這是它變得非常好的地方。別等。迴應客戶並感謝他們的訂單。所以現在你只需要3毫秒而不是20秒就把交易交給客戶。圍繞4個任務包裹一個try/catch並記錄任何失敗,以便有人可以工作。希望這已經完成,而不是告訴客戶哦,對不起,我們的郵件服務器已關閉。我聽到一些人稱這是遺忘和其他事情,這很糟糕。不算太差。這是很好的編程。固體主流線程/異步編程遲遲未能實現。購買永不使用的內核和內存以及處理響應速度慢的用戶等待坦誠地說他們不在乎的事情將有希望成爲過去。

這是任務/異步/等待。

var myTask = Task.Run(()=> {doSomething});.