2013-11-17 3 views
4

Сравните следующие два метода:Использует async/ждут лучше, чем использовать task.Start() и почему?

static async Task<int> DownloadAsync(string url) 
{ 
    var client = new WebClient(); 
    var awaitable = client.DownloadDataTaskAsync(url); 
    byte[] data = await awaitable; 
    return data.Length; 
} 

использование: Task<int> task = DownloadAsync("http://stackoverflow.com");

static Task<int> Download(string url) 
{ 
    var client = new WebClient(); 
    var task = client.DownloadDataTaskAsync(url); 
    byte[] data = task.Result; 
    return Task.FromResult(data.Length); 
} 

использование:

Task task = new Task(() => Download("http://stackoverflow.com")); 
task.Start(); 

Насколько я могу видеть оба метода выполняются асинхронно. Мои вопросы:
Есть ли разница в поведении между этими двумя методами?
Почему мы предпочитаем асинхронное ожидание другого, тогда это хороший шаблон?

+1

Обязательно используйте '.ConfigureAwait (false)' в методах, которые не требуют захвата 'SynchronizationContext', все ваши ожидания в' DownloadAsync' могли бы использовать это. См. [Здесь] (http://stackoverflow.com/a/13494570/921321) для объяснения, почему. – Lukazoid

ответ

3

new Task будет выполнять весь метод с использованием TaskScheduler.Current, как правило, это использует ThreadPool.

С помощью async/await метод вводится синхронно и будет использовать только асинхронное продолжение, если это необходимо.

То, что я имею в виду, может быть продемонстрирована с помощью следующей программы LINQPad:

const int delay = 1; 

public async Task DoSomethingAsync() 
{ 
    Thread.CurrentThread.ManagedThreadId.Dump(); 
    await Task.Delay(delay).ConfigureAwait(false); 
    Thread.CurrentThread.ManagedThreadId.Dump(); 
} 

void Main() 
{ 
    DoSomethingAsync().Wait(); 
} 

Попробуйте изменить delay 0, и вы увидите продолжение продолжается в том же потоке, это происходит потому, что Task.Delay просто возвращается немедленно, если нет задержки, это позволяет избежать накладных расходов на организацию и выполнение продолжений, когда они не требуются.

Используя new Task, вы теряете эту умную функциональность и всегда используете поток ThreadPool, даже если разработчик асинхронного метода не может считаться необходимым.

+0

Ваш ответ немного сложный, но вы указали реальную разницу в двух подходах. – Gerard

+0

@ Gerard Yeh, async/await немного сложно объяснить, особенно в 1.15 утра, я, может быть, попытаюсь улучшить его по утрам. – Lukazoid

+0

Метод без асинхронных прогонов в рабочем потоке полностью, метод с асинхронным ожиданием использует вызывающий поток до точки, где ожидает, то после ожидания он запускается в рабочем потоке, кроме как в примере задержки (0) - когда нет реальной задачи - она ​​снова запускается в вызывающем потоке. – Gerard

0

Посмотрите на это post, Стивен Клири объясняет, почему именно и почему.

Короче говоря, это совершенно то же самое. Это новый и старый способ ожидания. Я нахожу, что async/ждут приятнее на глазах, так как у вас будет дополнительный код в другом методе, и вам не нужно ставить задачу. Start().

7

Два метода, которые вы публикуете, совершенно разные.

DownloadAsync - действительно асинхронный метод. Это означает, что во время загрузки данных в этой асинхронной операции нет потоков, заблокированных.

Download синхронно блокирует вызывающий поток, вызывая Task.Result. Я объясняю в своем блоге why Result should not be used with asynchronous Tasks: в общем случае это может привести к блокировкам. Но давайте предположим, что нет тупика. Затем вы вызываете его из задачи TPL, поэтому он блокирует поток задачи (скорее всего, поток потока потока). Пока данные загружаются, этот поток задач блокируется при этой асинхронной операции.

Таким образом, DownloadAsync является более эффективным.

+0

'byte [] data = task.Result;' вызывается в рабочем потоке, так что только этот рабочий поток будет заблокирован. Я предполагаю, что соответствует 'byte [] data = await awaitable;' блокировка этого рабочего потока - isn ' t что правильно? Я верю в вашу статью, Результат вызывается в потоке пользовательского интерфейса и, следовательно, блокируется? – Gerard

+0

В деле 'DownloadAsync' нет рабочего потока. Проблема взаимоблокировки с 'Result' является проблемой * deadlock *, а не проблемой * блокировки *. Я рекомендую вам прочитать мой [intro to 'async'] (http://blog.stephencleary.com/2012/02/async-and-await.html) пост, если вы еще этого не сделали. –

+0

Чтение и понимание - это две разные вещи - helas;) – Gerard

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