2

Я использую TPL для сканирования набора Urls и последующей обработки.Отменить отмену задач и задач в Task.WaitAll?

for (int i = 0; i < list.Count; i++) 
{ 
    var tuple = list[i]; 
    string url = tuple.Item2; 

    tasks[i] = httpClient.GetStringAsync(url). 
     ContinueWith(task => { 
     { 
      ...... 

     }); 
} 
Task.WaitAll(tasks); 

Вопрос заключается в том, что на Task.WaitAll заявление, кажется, он будет часто бросать исключения, потому что задача была отменена. Я понимаю, что httpClient.GetStringAsync может не всегда обеспечивать успех, поэтому я хочу добавить логику повтора в httpClient.GetStringAsync, когда происходят исключения. Каким будет правильный подход к этому?

+0

Если повторная попытка не удалась, вы все еще хотите исключение? – i3arnon

+0

@ I3arnon: сделаю. Но тогда исключение будет передано как AggregateException в Task.WaitAll. Это правильно? – derekhh

+0

Да, потому что задача может содержать несколько исключений. Если вы будете «ждать Task.WhenAll», который был создан для 'async-await', тогда вы получите фактическое исключение внутри (первое из них). – i3arnon

ответ

2

Вы можете легко обернуть повторную попытку вокруг GetStringAsync с помощью цикла for, который пытается до тех пор, пока не будет никакого исключения или достигнут предел повтора. Я храню задачу и извлечь результат из него с помощью await так, если предел повторных попыток был достигнут без успеха, исключение будет вызвано повторно:

async Task<string> GetStringAsync(HttpClient client,string url, int retries) 
{ 
    Task<string> task = null; 
    for (int i = 0; i < retries; i++) 
    { 
     try 
     { 
      task = client.GetStringAsync(url); 
      await task; 
      break; 
     } 
     catch 
     { 
      // log 
     } 
    } 

    return await task; 
} 

Вы могли бы даже, что в качестве метода расширения на HttpClient:

static async Task<string> GetStringAsync(this HttpClient client, string url, int retries); 
0

Если вы не хотите использовать async/await, вы можете использовать следующий метод расширения в качестве отправной точки.

static class HttpClientExtentions 
{ 
    public static Task<string> GetStringWithRetryAsync(this HttpClient client, string url, int retries) 
    { 
     var completion = new TaskCompletionSource<string>(); 
     var ex = new List<Exception>(); 

     Task<string> getString = client.GetStringAsync(url); 
     Action<Task<string>> continueAction = null; 
     continueAction = (t) => 
     { 
      if (t.IsFaulted) 
      { 
       ex.Add(t.Exception); 

       if (retries-- > 0) 
       { 
        getString = client.GetStringAsync(url); 
        getString.ContinueWith(continueAction); 
       } 
       else 
       { 
        completion.SetException(new AggregateException(ex)); 
       } 
      } 
      else // assume success, you could also handle cancellation 
      { 
       completion.SetResult(t.Result); 
      } 

     }; 

     getString.ContinueWith(continueAction); 

     return completion.Task; 
    } 
} 

Используйте это следующим образом:

for (int i = 0; i < list.Count; i++) 
{ 
    var tuple = list[i]; 
    string url = tuple.Item2; 

    int retryCount = 3; 
    var httpClient = new HttpClient(); // should create new object for each req 
    tasks[i] = httpClient.GetStringWithRetryAsync(url, retryCount). 
     ContinueWith(task => { 
     { 
      //...... 

     }); 
} 
Task.WaitAll(tasks); 
Смежные вопросы