2012-11-08 26 views
0

我是一位TPL新手。不確定這個庫是否是要走的路,但我想按順序運行一組異步任務,但不阻止UI,但按照它們開始的順序依次運行和回調 - 有點像運行它們同步。所以只有在任務完成時纔有回調,並有一個HttpResponseMessage ..然後才能開始下一個任務。TPL - 按順序運行一系列.net 4.5休息查詢

所以行爲會

運行長時間運行的任務1,當其完成回調,使我們可以做一些與UI,然後 運行的下一個長期運行的任務,當其完成回調,使我們能更新UI。 運行較短的任務,當其完成回調,這樣我們就可以更新UI

我已經看到了一些例子,其中使用調度但無論如何,這裏是我的代碼

private void RunSequentially() 
{ 
     var lcts = new LimitedConcurrencyLevelTaskScheduler(1); 
     var factory = new TaskFactory(lcts); 
     string username = "user"; 
     string password = "password"; 
     var handler = new HttpClientHandler 
      { 
       Credentials = new NetworkCredential(username, password), PreAuthenticate = true 
      }; 
     var client = new HttpClient(handler); 

     List<Tuple<string,string,string>> taskTuples = new List<Tuple<string, string, string>>(); 
     taskTuples.Add(new Tuple<string, string, string>("POST", "http://longrunning", XDocument.Load(@"./somefile.xml").ToString())); 
     taskTuples.Add(new Tuple<string, string, string>("GET", "http://getItem", null)); 

     factory.StartNew(
      () => 
       { 
        foreach(var tuple in taskTuples) 
        { 
         ProcessSequentially(tuple,ProcessCallback, client); 
        } 
       }); 
    } 

而且ProcessSequentially方法

private async void ProcessSequentially(Tuple<string, string, string> tuple, Action<string> callback, HttpClient client) 
    { 
     HttpResponseMessage message = null; 
     if (tuple.Item1 == "POST") 
     { 
      message = await 
       client.PostAsync(
        tuple.Item2, 
        new StringContent(tuple.Item3)); 
     } 
     else 
     { 
      message = await 
       client.GetAsync(
        tuple.Item2); 
     } 

     callback(message.ReasonPhrase); 


    } 

現在假設post任務是長時間運行的 - 我需要長時間運行的一個首先啓動並回調,然後在第一個回調後不需要blo ck通過WaitAll等用戶界面有什麼辦法做到這一點可能作爲TPL或TPL數據流中的事務,因爲當我運行這個時,POST首先開始,但因爲get是一個快速操作,它首先完成並且首先返回,我希望它們按照同步操作的順序發生...

所以,爲了更改代碼 - 這是更好的方法嗎?

foreach (var tuple in taskTuples) 
     { 
      factory.StartNew(
      () => 
      { 
       this.ProcessSequentially(tuple,client); 
      }).ContinueWith(this.FinishSequentialTask); 
     } 
+1

'Task.ContinueWith'? –

+0

再一次,強調我是新來的 - 從我讀過的 - 我曾認爲await關鍵字正在執行引擎蓋下的延續。 –

+0

這只是另一種鏈接任務的方式。 –

回答

1

你想連續異步代碼。 await是這一個完美的結合:

private async Task RunSequentially() 
{ 
    string username = "user"; 
    string password = "password"; 
    var handler = new HttpClientHandler 
    { 
    Credentials = new NetworkCredential(username, password), PreAuthenticate = true 
    }; 
    var client = new HttpClient(handler); 

    List<Tuple<string,string,string>> taskTuples = new List<Tuple<string, string, string>>(); 
    taskTuples.Add(new Tuple<string, string, string>("POST", "http://longrunning", XDocument.Load(@"./somefile.xml").ToString())); 
    taskTuples.Add(new Tuple<string, string, string>("GET", "http://getItem", null)); 
    foreach (var tuple in taskTuples) 
    { 
    await Process(tuple, ProcessCallback, client); 
    } 
} 

private async Task Process(Tuple<string, string, string> tuple, Action<string> callback, HttpClient client) 
{ 
    HttpResponseMessage message = null; 
    if (tuple.Item1 == "POST") 
    { 
    message = await 
     client.PostAsync(
      tuple.Item2, 
      new StringContent(tuple.Item3)); 
    } 
    else 
    { 
    message = await 
     client.GetAsync(
      tuple.Item2); 
    } 

    callback(message.ReasonPhrase); 
} 

private void ProcessCallback(string reason); 

這種簡單的方法將UI線程同步執行ProcessCallback。如果您需要ProcessCallback異步的,你可以做:

private async Task Process(Tuple<string, string, string> tuple, Func<string, Task> callback, HttpClient client) 
{ 
    HttpResponseMessage message = null; 
    if (tuple.Item1 == "POST") 
    { 
    message = await 
     client.PostAsync(
      tuple.Item2, 
      new StringContent(tuple.Item3)); 
    } 
    else 
    { 
    message = await 
     client.GetAsync(
      tuple.Item2); 
    } 

    await callback(message.ReasonPhrase); 
} 

private async Task ProcessCallback(string reason); 

附:我離開了你的Tuple以儘量減少代碼更改,但我建議你用自定義類型替換它們;它使代碼更清晰。

+0

是的確 - 第二種方法正是我所需要的,因爲我不想阻止UI線程。 –