2016-07-20 3 views
1

Я не могу найти никакой информации о фактической разнице.Разница между ожиданием сразу или ожиданием позже

Так что я всегда делал следующее:

public async Task<int> DoSomethingAsync() 
{ 
    DoSomethingElse() 
    var result = await GetValueAsync(); 
    var intValue = DoAnotherThing(result); 
    return intValue; 
} 

await вызов, а затем использовать его сразу после, но я видел в последнее время несколько постов, где люди делают следующее:

public async Task<int> DoSomethingAsync() 
{  
    var task = GetValueAsync(); 
    DoSomethingElse() 
    var result = await task; 
    var intValue = DoAnotherThing(result); 
    return intValue; 
} 

Значит ли это, что метод GetValueAsync начинает его выполнение, а затем мы ожидаем его результата позже? Или это означает, что он выполняется синхронно, но все же можно использовать await?

+5

Это означает, что ваше первое предположение. –

+1

Многие люди думают, что 'await' * начинает * что-то происходит. Это совершенно неправильно. 'await' просто ждет чего-то, чтобы закончить - как это было начато, это полностью деталь реализации других вещей - в этом случае, как« GetValueAsync »внутренне реализован. –

+1

До сих пор три ответа не обсуждали созданный конечный автомат, который, я думаю, тоже потенциально важный для понимания. –

ответ

4

Damien_The_Unbeliever прав, когда он говорит, что это зависит от реализации.

class Program 
{ 
    public static int DoAnotherThing(string value) 
    { 
     return int.Parse(value); 
    } 

    public static async Task<string> GetValueAsync() 
    { 
     await Task.Delay(5000); 
     return "12"; 
    } 

    public static void DoSomethingElse() 
    { 
     Thread.Sleep(5000); 
    } 

    public static async Task<int> DoSomethingAsyncA() 
    { 
     DoSomethingElse(); 
     var result = await GetValueAsync(); 
     var intValue = DoAnotherThing(result); 
     return intValue; 
    } 

    public static async Task<int> DoSomethingAsyncB() 
    { 
     var task = GetValueAsync(); 
     DoSomethingElse(); 
     var result = await task; 
     var intValue = DoAnotherThing(result); 
     return intValue; 
    } 

    public static void Measure(Action act) 
    { 
     var sw = new Stopwatch(); 

     sw.Start(); 

     act(); 

     sw.Stop(); 

     Console.WriteLine(sw.Elapsed); 
    } 

    static void Main(string[] args) 
    { 
     Measure(() => DoSomethingAsyncA().Wait()); 
     Measure(() => DoSomethingAsyncB().Wait()); 

     Console.ReadLine(); 
    } 
} 

В этом случае DoSomethingAsyncB займет ~ 5 секунд, где DoSomethingAsyncA будет принимать 10 ~. Однако, если ваш GetValueAsync возвращает вычисление значения, которое было запущено где-то в другом месте, тогда не будет никакой разницы.

ОБНОВЛЕНИЕ Я исправил ошибку в ответе. И вот вывод с моей машины:

00:00:10:0161446 
    00:00:05:0032000 
+0

'DoSomethingAsyncB' займет 5 секунд и 10? –

+1

Приносим извинения за опечатку. Я исправил ответ. – derwasp

3

В этом

public async Task<int> DoSomethingAsync() 
{ 
    DoSomethingElse() 
    var result = await GetValueAsync(); 
    var intValue = DoAnotherThing(result); 
    return intValue; 
} 

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

ниже код означает:

public async Task<int> DoSomethingAsync() 
{  
    var task = GetValueAsync(); 
    DoSomethingElse() 
    var result = await task; 
    var intValue = DoAnotherThing(result); 
    return intValue; 
} 

Вы называете GetValueAsync и сделать DoSomethingElse во время ожидания GetValueAsync, чтобы закончить его, а затем, когда она будет закончена она продолжает выполняться DoAnotherThing

0

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

1

В первом примере вы не будете выполнять код до того, как GetValueAsync() вернет результат.

Во втором - вы выполните код между var task = GetValueAsync(); и var result = await task; - вы выполните DoSomethingElse().

Смотрите небольшой пример:

public static Task<int> DoLongOperationAsync() 
    { 
     return Task.Run(() => { Thread.Sleep(5000); return 5; }); // 5 seconds 
    } 


    public static async Task TestMethod() 
    { 
     var result = await DoLongOperationAsync(); 
     Console.WriteLine("Console"); 
     Console.WriteLine(result); 
    } 

    public static async Task TestMethod2() 
    { 
     var result = DoLongOperationAsync(); 
     Console.WriteLine("Console"); 
     Console.WriteLine(await result); 
    } 


    static async DoSomething() 
    { 
     await TestMethod(); // here you see some text in console only after 5 seconds 

     await TestMethod2(); // here you see some text in console immediately and after 5 seconds you will see "5" 

    } 
2

Нередко люди думают, что асинхронное ожидание выполняется несколькими потоками. Обычно это не так. Если вы не запускаете другие потоки, весь код выполняется одним и тем же потоком. Проверка ThreadId текущего потока покажет вам это.

В interview Eric Lippert explained async-await in a restaurant metaphor. Искать где-нибудь посередине для асинхронного ожидания.

Он объясняет, что если повар тост за хлебом, он может подождать, пока хлеб не поджарится или не начнет делать что-то еще, и вернется позже, чтобы посмотреть, закончит ли тостер тосты.

То же самое происходит во втором DoSomethingAsync. При записи даты на диск ваш поток передает данные автору диска. Запись на диски - относительно медленный процесс. Нить не ждет, когда будет написана дата, вместо этого она начинает делать что-то еще. Когда он закончит делать что-то еще, поток ждет, пока запись на диск не закончит запись на диск.

Это полезно, только если запись на диске может продолжаться, пока ваш поток выполняет что-то еще. Поэтому вы обычно видите функции async, когда задействовано оборудование, или процессы, которые запускают другие потоки, чтобы выполнить какую-либо работу. Если функция async должна выполнять некоторые трудоемкие вычисления, не полезно делать функцию async, если только она не запускает другой поток для выполнения вычислений. Даже тогда сомнительно, должно ли это быть сделано внутри асинхронной функции или же у вызывающего лица должна быть свобода решать, разрешать ли его собственный поток выполнять вычисления или запускать другой поток для этого.

Another article that helped me to understand async-await by Stephen Cleary, большой вклад в этот сайт (еще раз спасибо Стивен!)

+0

Хороший пример. Благодарю. –

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