2015-10-02 184 views
1

我正在處理一系列使用實體框架執行許多不同數據庫調用的方法。許多這些方法可以異步運行,因爲我真的不關心它們的輸出,也不依賴它們。不等待異步編程?

然而,當我嘗試實現某些方法,我從編譯器說一個警告:「因爲這個呼叫沒有等待,目前的方法繼續完成之前調用運行」

但對我來說,這看起來像是我期望的行爲,因爲我不在乎這些方法做什麼。

這裏的方法的一個例子

public async Task SetupAccessControl(int objectTypeId, int objectId, int? organizationId) 
{ 
    using (var context = new SupportContext(CustomerId)) 
    { 
     ... // omitted for brevity 
     if (objectTypeId == (int) ObjectType.User) 
     { 
      AddToUserRoleBridge("Everyone", objectId);//Warning on this line 
      AddToUserRoleBridge("Default", objectId); //Warning on this line 
     } 
     ... // omitted for brevity 
    } 
} 

public async Task AddToUserRoleBridge(string role, int userId) 
{ 
    using (var context = new SupportContext(CustomerId)) 
    { 
     var defaultRole = context.Roles.FirstOrDefault(n => n.Name == role); 
     if (defaultRole != null) 
     { 
      var urb = new UserRoleBridge 
      { 
       RoleId = defaultRole.Id, 
       UserId = userId 
      }; 

      context.UserRoleBridges.Add(urb); 
      await context.SaveChangesAsync(); 
     } 
    } 
} 

編輯

從本質上講,當我運行的主要功能,我想了一系列的方法有所同時呼籲所有消防關閉和處理一切他們自己的線程,這樣我就不必擔心它。這是一個僞代碼示例。

public async void RunAllAsync() { 
    taskA(*some value*); 
    taskA(*some value*); 
    taskB(*some value*); 
    taskB(*some value*); 

    await AllTasksCompleted 
} 

public async Task taskA(int item){ 
    //do something with item 
} 


public async Task taskB(int item) { 
    subTaskB(*some value*) 
    subTaskB(*some value*) 
} 

public async Task subTaskB(int item) { 
    // do something 
} 

在上面的例子中,當#RunAllAsync被調用,每個函數調用它使(和函數調用他們做)同時發射了。當所有這些調用都完成後,將繼續執行任何名爲#RunAllAsync的方法。

+0

看看這個:https://msdn.microsoft.com/en-us/library/hh191443.aspx?f=255&MSPPError=-2147217396有一個很好的圖表顯示了異步方法的運行方式。 –

+0

在任務完成之前,程序是否仍然正確執行?如何處理例外情況,這是你永遠不會看到的?這些問題的正確答案几乎總是一個響亮的*否*。 [閱讀本文](http://blogs.msdn.com/b/pfxteam/archive/2012/09/11/forking-in-async-methods.aspx)。 –

+0

'因爲我不在乎方法做什麼'真的嗎?你確定? *他們完成時你不關心*你不關心*他們是否完成?你不在乎他們是否拋出異常*?儘管真實的「即將發生的」情景*可能發生,但它遠不如大多數人想象的那麼普遍。 –

回答

2

如果您沒有使用await,則async關鍵字沒有任何實際用處,您可以將其關閉。無論是否標記爲異步,您都可以等待返回Task的方法。

public Task DoSomethingAsync() 
{ 
    Task someTaskJustLikeANormalReturnValue = Task.Delay(1000); 
    return someTaskJustLikeANormalReturnValue; 
} 

// later... 
public async Task SomeOtherFunction() 
{ 
    // You can await DoSomethingAsync just like any async method, because 
    // you're really awaiting the Task which got returned. 
    await DoSomethingAsync(); 
} 

在你的情況,我可能會收集任務,並等待他們一起:

public async Task SetupAccessControl(int objectTypeId, int objectId, int? organizationId) 
    { 
     var tasks = new List<Task>(); 
     using (var context = new SupportContext(CustomerId)) 
     { 
      ... // omitted for brevity 
      if (objectTypeId == (int) ObjectType.User) 
      { 
       tasks.Add(AddToUserRoleBridge("Everyone", objectId)); 
       tasks.Add(AddToUserRoleBridge("Default", objectId)); 
      } 
      ... // omitted for brevity 
     } 

     await Task.WhenAll(tasks.ToArray()); 
    } 

這允許用戶最多通過的決定,是否要在子任務或不等待來電。這也將允許任何呼叫者在AddToUserRoleBridge中發生任何異常情況。

+0

「async關鍵字的唯一功能是啓用await關鍵字。」那麼,不是真的。它還會更改異常如何傳播以及如何包裝返回值。 –

+0

的確,我重寫了第一句話,以使其更準確並與問題相關。 – Erik

+0

雖然第一句話仍然不正確。考慮:'公共任務Foo(){}'不會編譯。 '公共異步任務Foo(){}'會。 –

1

你可以做到這一點有兩種方式:

  • 變化AddToUserRoleBridge的簽名返回void將 刪除警告(但沒有什麼可以等待它,然後)。
  • 存儲呼叫的結果。 var ignoreme=AddToUserRoleBridge(...)也會刪除警告。
+0

雖然這確實回答你的問題,但我強烈建議Erik的回答。 –