2014-06-08 50 views
3

下面的方法之間是否有區別?一個比另一個更好嗎?在異步方法中返回和等待任務之間的區別

public static async Task SendAsync1(string to, string subject, string htmlBody) { 
    // ... 
    await smtp.SendMailAsync(message); 
    // No return statement 
} 

public static Task SendAsync2(string to, string subject, string htmlBody) { 
    // ... 
    return smtp.SendMailAsync(message); 
} 

該方法將從MVC控制器方法調用;例如:

public async Task<ActionResult> RegisterUser(RegisterViewModel model) 
{ 
    // ... 
    await Mailer.SendAsync(user.Email, subject, body); 
    return View(model); 
} 
+0

也許在2處保持的狀態(通過異步/ AWAIT狀態機構)的成本如果使用SendAsync1,但也許async/await狀態機足夠聰明,可以優化這個問題......只是一個想法,它很有趣。 – brumScouse

回答

5

有2個實用的差異:

  1. 第二個選項不會創建狀態機mecanism允許async-await使用。這將對次要的性能產生正面影響。
  2. 異常處理將有所不同。當您將方法標記爲async時,任何異常都存儲在返回的任務中(來自異步部分和同步部分)並且僅在等待(或等待)該任務時拋出。當它不是async時,來自同步部分的異常就像在其他任何方法中一樣。

我的建議:使用第二個增加的性能提升,但留意異常和錯誤。


,顯示差的一個例子:

public static async Task Test() 
{ 
    Task pending = Task.FromResult(true); 
    try 
    { 
     pending = SendAsync1(); 
    } 
    catch (Exception) 
    { 
     Console.WriteLine("1-sync"); 
    } 

    try 
    { 
     await pending; 
    } 
    catch (Exception) 
    { 
     Console.WriteLine("1-async"); 
    } 

    pending = Task.FromResult(true); 
    try 
    { 
     pending = SendAsync2(); 
    } 
    catch (Exception) 
    { 
     Console.WriteLine("2-sync"); 
    } 

    try 
    { 
     await pending; 
    } 
    catch (Exception) 
    { 
     Console.WriteLine("2-async"); 
    } 
} 

public static async Task SendAsync1() 
{ 
    throw new Exception("Sync Exception"); 
    await Task.Delay(10); 
} 

public static Task SendAsync2() 
{ 
    throw new Exception("Sync Exception"); 
    return Task.Delay(10); 
} 

輸出:

1-async 
2-sync 
3

await旨意導致編譯器創建一個狀態機,因爲一旦the await關鍵字匹配的方法將返回給調用者,一旦期待已久的部分完成它有你的第一個方法從停止點恢復。

但是,由於您在等待(沒有延續)後沒有做任何事情,因此不需要該狀態機。

第二種方法是首選在這種情況下,您可以不從它的async關鍵字,因爲你沒有任何等待

3

首先,我不認爲在您的示例代碼編譯。您需要從SendAsync2中刪除「async」關鍵字。

如果你這樣做,那麼這些方法可以互換使用,所以不,在這種情況下沒有區別。我寧願沒有異步/等待的那個。

但是,有些情況似乎沒有區別,但區別在於細節。例如,考慮下面的代碼:

async Task<X> Get() 
{ 
    using (something) 
    { 
      return await GetX(); 
    } 
} 

如果你把這裏改爲:

Task<X> Get() 
{ 
    using (something) 
    { 
     return GetX(); 
    } 
} 

那麼using塊不再保護封裝在X執行,並something將早於它會佈置在第一種情況下。例如當something是實體框架上下文時很重要。

try塊內的return await也是一樣。

+0

很好的觀察潛在問題的周圍使用/ try-catch! –