2014-02-22 25 views
6

在下面的代碼中,我需要並行執行三個Get ...方法。當Get ...方法完成時,我需要立即調用Save ...方法。注意保存...將事物作爲參數。 所有獲取和保存方法必須在DoStuffAsync返回之前完成。async/await continuation

我的猜測是我需要Get ...方法的延續,但我不知道如何構造它。

protected async void DoStuffAsync() 
{ 
    SomeThing thing = new SomeThing { ID = 5 }; 
    SomeRepository rep = new SomeRepository(); 

    // We need to run all three Get... methods in parallel 
    // As soon as a Get... method completes we need to save the result to the correct property on thing and call the Save... method . 

    var getRed = rep.GetRedAsync().ContinueWith<Task<string>>(async x => { thing.Color1 = x.Result; await rep.SaveRedAsync(thing); return x; }); // does not compile 
    var getBlue = rep.GetBlueAsync(); 
    var getGreen = rep.GetGreenAsync(); 

    string red = await getRed.Result; // this is not good because getBlue may finish before getRed. We want dont want to wait on getRed before calling SaveBlue 
    await rep.SaveRedAsync(thing); 
    var b = await getBlue; 
    var c = await getGreen; 

    // thing must be fully initialized before DoStuffAsync returns 

    } 


public class SomeThing 
{ 
    public int ID { get; set; } 
    public string Color1 { get; set; } 
    public string Color2 { get; set; } 
    public string Color3 { get; set; } 
} 

public class SomeRepository 
{ 
    public async Task<string> GetRedAsync() 
    { 
     return await Task.Run(() => "red"); 
    } 

    public async Task<string> GetBlueAsync() 
    { 
     return await Task.Run(() => "blue"); 
    } 

    public async Task<string> GetGreenAsync() 
    { 
     return await Task.Run(() => "green"); 
    } 

    public async Task SaveRedAsync(SomeThing thing) 
    { 
     // We need thing.ID here as well as other properties 
     await Task.Delay(1); 
    } 

    public async Task SaveBlueAsync(SomeThing thing) 
    { 
     await Task.Delay(1); 
    } 

    public async Task SaveGreenAsync(SomeThing thing) 
    { 
     await Task.Delay(1); 
    } 
} 
+5

當您認爲可以正常工作但未編譯的代碼時,請包含編譯錯誤。 –

回答

7

我不會混ContinueWithawait和而使用直接的async拉姆達:

protected async Task DoStuffAsync() 
{ 
    SomeThing thing = new SomeThing { ID = 5 }; 
    SomeRepository rep = new SomeRepository(); 

    // We need to run all three Get... methods in parallel 
    // As soon as a Get... method completes we need to save the result to the correct property on thing and call the Save... method . 

    Func<Task<X>> getRedFunc = async() => 
    { 
     var result = await rep.GetRedAsync(); 
     thing.Color1 = result; 
     await rep.SaveRedAsync(thing); 
     return result; 
    }; 

    var getRed = getRedFunc(); 

    var getBlue = rep.GetBlueAsync(); 
    var getGreen = rep.GetGreenAsync(); 

    await Task.WhenAll(getRed, getBlue, getGreen); 
} 

另外,不要使用async void方法什麼,但事件處理程序。你將無法觀察到像這樣的方法的完成,或者處理可能拋出的異常。

+1

謝謝Noseratio – user579342

+0

你有沒有理由背後「我不會混合ContinueWith和等待?」 – NStuke

+0

@NStuke,不一定按照這個順序,但是:1)代碼結構和可讀性; 2)當前'SynchronizationContext'和'TaskScheduler'被考慮的差異,3)異常處理和傳播方式的差異; 4)延續lambda運行方式的差異(人們往往會忘記ExecuteSynchronously); 5)我確定我錯過了其他的東西,但那應該足夠了:) – Noseratio

7

好了,你可以明確使用ContinueWith - 或者你可以中斷每個「獲取和保存」到一個單獨的異步方法或異步拉姆達。例如:

async Task GetAndSaveRedAsync(SomeThing thing, SomeRepository rep) 
{ 
    var red = await rep.GetRedAsync(); 
    thing.Red = red; 
    await SaveRedAsync(red); 
    // Return red if you want (change the return type to Task<string>) 
} 

// Ditto for the others 

然後:

protected async void DoStuffAsync() 
{ 
    SomeThing thing = new SomeThing { ID = 5 }; 
    SomeRepository rep = new SomeRepository(); 

    var handleRed = GetAndSaveRedAsync(thing, rep); 
    var handleBlue = GetAndSaveBlueAsync(thing, rep); 
    var handleYellow = GetAndSaveYellowAsync(thing, rep); 

    // Or use Task.WhenAll 
    await handleRed; 
    await handleBlue; 
    await handleYellow; 
} 
+0

爲什麼有人會寫一個異步任務,等待另一個任務。爲什麼不寫一個任務,並在這個調用中「正常」而不是異步方法。由於您的任務已經在另一個線程上運行,因此synchc方法不會阻止用戶界面。但是在任務中調用一個任務並等待這個任務不是不必要的開銷? –

+4

@RandRandom:是什麼讓你認爲任何東西都在不同的線程上運行?是的,你*可以*使用'Task.Run'併爲此專用一個線程,但爲什麼你想要創建比你需要的線程更多的線程呢? –

+0

所以我想你是說一個任務不能在不同的線程上運行?我認爲這是你編寫任務的唯一原因,因此它可以在不同的線程中運行異步。 –

-1

您可以嘗試並行框架:

using System.Threading; 

using System.Threading.Tasks; 

Func<Task<string>>[] functions = { rep.GetRedAsync, rep.GetBlueAsync, rep.GetGreenAsync }; 
Var[] GetArray = new Var[functions.Length] 
int i=0; 
Parallel.ForEach (var function in functions) 
{ 
      GetArray[i++]=function(); 

} 

注意:要求.Net 4

相關問題