2016-06-10 3 views
0

Я новичок в C#, и пока я пытаюсь понять async/await feautures. Таким образом, я создал небольшую песочницу приложения:C# async ждет странное поведение

namespace sandbox 
{ 
public class Test 
{ 
    public async Task<string> GetItemsAsync() 
    { 
     var a = await Task1(); 
     var b = await Task2(); 
     var c = await Task3(); 

     return a + b + c; 
    } 

    public string GetItems() 
    { 
     return _T1() + _T2() + _T3(); 
    } 

    private readonly int cycles = 100000000; 

    private async Task<string> Task1() 
    { 
     return await Task.Factory.StartNew(_T1); 
    } 

    private async Task<string> Task2() 
    { 
     return await Task.Factory.StartNew(_T2); 
    } 

    private async Task<string> Task3() 
    { 
     return await Task.Factory.StartNew(_T3); 
    } 

    // long running operation 
    private string _T1() 
    { 
     for (int i = 0; i < cycles; i++) ; 
     for (int i = 0; i < cycles; i++) ; 
     return "One"; 
    } 

    // long running operation 
    private string _T2() 
    { 
     for (int i = 0; i < cycles; i++) ; 
     for (int i = 0; i < cycles; i++) ; 
     return "Two"; 
    } 

    // long running operation 
    private string _T3() 
    { 
     for (int i = 0; i < cycles; i++) ; 
     for (int i = 0; i < cycles; i++) ; 
     return "Three"; 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var t = new Test(); 

     Console.WriteLine("Async"); 
     Stopwatch sw = new Stopwatch(); 
     sw.Start(); 
     var result = t.GetItemsAsync(); 
     Console.WriteLine(result.Result); 
     sw.Stop(); 
     Console.WriteLine(sw.ElapsedMilliseconds); 

     Console.WriteLine("Sync"); 
     sw.Restart(); 
     var strResult = t.GetItems(); 
     Console.WriteLine(strResult); 
     sw.Stop(); 
     Console.WriteLine(sw.ElapsedMilliseconds); 

     Console.ReadLine(); 
    } 
} 
} 

Но результат странно:

Async 
OneTwoThree 
1754 
Sync 
OneTwoThree 
1506 

метод Асинхронного работает дольше, чем аналогичные синхронизации один. Для меня это похоже, что методы async работают синхронно, но я не могу понять, почему.

+3

Потому что вы ожидаете их всех синхронно. – Liam

+1

, ожидая задачи, вы меняете ее с асинхронного на синхронный, ключевое слово await переводит приостановку текущей задачи и не продолжается до тех пор, пока ожидаемая задача не завершится – MikeT

+0

Использование ожидания приведет к тому, что код будет выполняться синхронно, а также добавьте накладные расходы создание конечного автомата (каждый раз, когда вы используете 'await'), поэтому он также медленнее, чем запуск их синхронно. – Igor

ответ

4

Из-за этого:

var a = await Task1(); 
var b = await Task2(); 
var c = await Task3(); 

Прежде чем начать Task2 вы ждали Task1, чтобы закончить. Таким образом, вы не запускаете их параллельно, вы запускаете их последовательно.

Если вы хотите, чтобы начать все 3 задачи, а затем ждать их завершения вы должны изменить этот метод следующим образом:

public async Task<string> GetItemsAsync() 
{ 
    var t1 = Task1(); 
    var t2 = Task2(); 
    var t3 = Task3(); 

    var a = await t1; 
    var b = await t2; 
    var c = await t3; 

    return a + b + c; 
} 

или только последнюю часть:

return (await t1) + (await t2) + (await t3); 

Дополнительно этот код является антипаттерн:

private async Task<string> Task3() 
{ 
    return await Task.Factory.StartNew(_T3); 
} 

Вам не нужно async/await здесь becaus e вы не делаете больше работы в этом методе после того, как ваша подзадача возвращает.

Вместо просто переписать этот метод (и его братьев и сестер) к этому:

private Task<string> Task3() 
{ 
    return Task.Factory.StartNew(_T3); 
} 
+0

Что вы подразумеваете под «не начатыми задачами»? Это ответственность за эти 3 метода, которые явно начинают новые задачи. Я не обязан начинать задание *, если эта задача была возвращена мне *. Это несет ответственность за то, что оно вернуло *. Во всяком случае, эти задачи четко начаты, «Task.Factory.StartNew». –

+0

Извиняется, что я неправильно прочитал их код и не заметил запусков внутри методов задачи. – MikeT

+1

Операция * * может * elide 'async' /' await'; Тем не менее, я бы не зашел так далеко, чтобы назвать это анти-шаблоном. Что определенно * анти-шаблон - это использование «StartNew» без указания планировщика задач (вместо этого следует использовать «Task.Run'). Кроме того, вы можете сделать сильный аргумент в пользу того, что возвращение задачи «StartNew' /' Run »также является анти-шаблоном (синхронный код должен иметь синхронные API-интерфейсы, * вызывающий * должен решить, следует ли нажать на пул потоков). –

0

Я подозреваю, что намерение состояло в том, чтобы сделать все три задачи сделать работу параллельно. Это один из вариантов того, как это можно сделать:

public async Task<string> GetItemsAsync() 
{ 
    var a = Task1(); 
    var b = Task2(); 
    var c = Task3(); 

    return string.Concat(await Task.WhenAll(a, b, c)); 
} 
Смежные вопросы