2014-11-04 3 views
2

Я читал несколько блогов о async & ждут, в частности, Scott's blog. У меня есть пример кода ниже, который предположительно загружает список URL-адресов. Чтобы упростить вещи и сделать тайминги разумными и повторяемыми, я заменил реальный код загрузки Task.Delay ожидаемый вызов.async ждут (снова) внутри lambda

Первый код не имеет пары асинхронного ожидания внутри выражения лямбда, а второй имеет. Оба кода компилируются, и оба тайм-кода выходят одинаково (около 1 секунды).

1.) Какой метод является правильным способом?

2.) Ожидает ли асинхронная пара внутри лямбда больше?

private async void Button_Click(object sender, RoutedEventArgs e) 
{ 
    // Capture the UI synchronization context for use later 
    var ui = TaskScheduler.FromCurrentSynchronizationContext(); 

    // sample 1 , is this the right way? 
    var items = Enumerable.Range(1, 100) 
    .Select(i => i.ToString()) 
    .ToList(); 

    var sp = new Stopwatch(); 
    sp.Start(); 

    // NO await async pair in lambda 
    var results1 = await Task.WhenAll(items.Select(item => DownloadFileAsync(item))); 

    sp.Stop(); 
    var testResult = string.Format("Single await: {0} seconds", sp.Elapsed.TotalSeconds); 

    // sample 2, or this way? 
    var items1 = Enumerable.Range(1, 100) 
    .Select(i => i.ToString()) 
    .ToList(); 

    var sp1 = new Stopwatch(); 
    sp1.Start(); 

    // WITH await async pair in lambda 
    var results = await Task.WhenAll(items1.Select(async item => await DownloadFileAsync(item))); 

    sp1.Stop(); 
    var testResult1 = string.Format("Double await: {0} seconds", sp1.Elapsed.TotalSeconds); 

    // show results 

    await Task.Factory.StartNew(() => 
    { 
     MessageBox.Show(testResult + System.Environment.NewLine + testResult1); 
    }, CancellationToken.None, TaskCreationOptions.None, ui).ConfigureAwait(false); 

} 

private async Task<string> DownloadFileAsync(string uri) 
{ 
    //using (var client = new WebClient()) 
    //{ 
    // string data = await client.DownloadStringTaskAsync(uri).ConfigureAwait(false); 
    // return data; 
    //} 

    await Task.Delay(1000).ConfigureAwait(false); 
    return uri; 


} 

ответ

4

Оба они примерно эквивалентны. Первый из них несколько эффективнее.

Для целей этого вопроса вы можете представить await как «разворачивание» задачи, а async - как «обертывание» метода в задаче. В первом примере используется лямбда-выражение для определения функции с сигнатурой Task<string> F(string). Функция, определенная вторым примером, имеет одну и ту же подпись. Разница в том, что первый пример просто возвращает задачу с DownloadFileAsync, а второй пример разворачивает задачу, а затем снова завершает ее.

+0

Есть ли другой способ «визуально» увидеть разницу? Например. просматривая код IL? – alpinescrambler

+0

@alpinescrambler: Да; код, сгенерированный компилятором, чрезвычайно отличается. –

Смежные вопросы