Подтвердить что ты не робот

Как я могу запускать оба этих метода "одновременно" в .NET 4.5?

У меня есть метод, который делает две независимые части логики. Я надеялся, что я смогу запустить их обоих одновременно... и только потом, когда оба этих дочерних метода завершатся.

Я пытался разглядеть синтаксис async/await, но я просто не понимаю.

Здесь код:

public PewPew SomeMethod(Foo foo)
{
    var cats = GetAllTheCats(foo);
    var food = GetAllTheFood(foo);

    return new PewPew
               {
                   Cats = cats,
                   Food = food
               };
}

private IList<Cat> GetAllTheCats(Foo foo)
{
    // Do stuff, like hit the Db, spin around, dance, jump, etc...
    // It all takes some time.
    return cats;
}

private IList<Food> GetAllTheFood(Foo foo)
{
    // Do more stuff, like hit the Db, nom nom noms...
    // It all takes some time.
    return food;
}

Итак, с этим кодом выше, я хочу сказать: идите и получите всех кошек и продуктов питания в одно и то же время. Как только мы закончим, вернем новый PewPew.

Я смущен, потому что я не уверен, какие классы выше async или возвращают Task и т.д. Все из них? просто две частные? Я также предполагаю, что мне нужно использовать метод Task.WaitAll(tasks), но я не уверен, как настроить задачи для запуска в одно и то же время.

Предложения, добрые люди?

4b9b3361

Ответ 1

Вот что вы можете сделать:

public async Task<PewPew> SomeMethod(Foo foo)
{
    // get the stuff on another thread 
    var cTask = Task.Run(() => GetAllTheCats(foo));
    var fTask = Task.Run(() => GetAllTheFood(foo));

    var cats = await cTask;
    var food = await fTask;

    return new PewPew
               {
                   Cats = cats,
                   Food = food
               };
}

public IList<Cat> GetAllTheCats(Foo foo)
{
    // Do stuff, like hit the Db, spin around, dance, jump, etc...
    // It all takes some time.
    return cats;
}

public IList<Food> GetAllTheFood(Foo foo)
{
    // Do more stuff, like hit the Db, nom nom noms...
    // It all takes some time.
    return food;
}

Здесь вам нужно понять две вещи:

1) Что такое diff:

var cats = await cTask;
var food = await fTask;

И это:

Task.WaitAll(new [] {cTask, fTask});

Оба дают вам аналогичный результат в том смысле, что заканчиваются задачи 2 async, а затем return new PewPew - однако разница заключается в том, что Task.WaitAll() будет блокировать текущий поток (если это поток UI, тогда UI замерзнет). вместо этого await разбивает SomeMethod на конечный автомат и возвращает из SomeMethod его вызывающему, когда он встречает ключевое слово await. Он не будет блокировать поток. Код ниже await будет запланирован для запуска, когда задача async завершена.

2) Вы также можете сделать это:

var cats = await Task.Run(() => GetAllTheCats(foo));
var food = await Task.Run(() => GetAllTheFood(foo));

Однако это не будет запускать задачи async одновременно. Вторая задача начнется после завершения первого. Это связано с тем, что работает ключевое слово await, надеюсь, что это поможет...

EDIT: как использовать SomeMethod - где-то в начале дерева вызовов, вы должны использовать свойство Wait() или Result - ИЛИ - вы должны await от async void. Как правило, async void будет обработчиком событий:

public async void OnSomeEvent(object sender, EventArgs ez) 
{ 
  Foo f = GetFoo();
  PewPew p = await SomeMethod(f);
}

Если нет, используйте свойство Result.

public Foo2 NonAsyncNonVoidMethod() 
{
   Foo f = GetFoo();
   PewPew p = SomeMethod(f).Result; //But be aware that Result will block thread

   return GetFoo2(p);
}

Ответ 2

Самый простой способ сделать это - использовать Parallel.Invoke()

IList<Cat> cats;
IList<Food> food;

Parallel.Invoke
(
    () => cats = GetAllTheCats(foo),
    () => food = GetAllTheFood(foo)
);

Parallel.Invoke() будет ждать, пока все методы вернутся, прежде чем он сам вернется.

Дополнительная информация здесь: http://msdn.microsoft.com/en-us/library/dd460705.aspx

Обратите внимание, что Parallel.Invoke() обрабатывает масштабирование до числа процессоров в вашей системе, но это действительно имеет значение, если вы начинаете больше, чем просто несколько задач.

Ответ 3

Вам не нужно использовать async, если вы не используете метод async или используете более старую версию .NET Framework. Для простоты используйте Задачи:

Task taskA = Task.Factory.StartNew(() => GetAllTheCats(foo));
Task taskB = Task.Factory.StartNew(() => GetAllTheFood(foo));

Task.WaitAll(new [] { taskA, taskB });
// Will continue after both tasks completed

Ответ 4

Вы можете использовать TPL, чтобы ждать нескольких задач во время их работы. См. здесь.

Вот так:

public PewPew SomeMethod(Foo foo) {
    IList<Cat> cats = null;
    IList<Food> foods = null;

    Task[] tasks = new tasks[2] {
        Task.Factory.StartNew(() => { cats = GetAllTheCats(foo); }),
        Task.Factory.StartNew(() => { food = GetAllTheFood(foo); })
    };

    Task.WaitAll(tasks);

    return new PewPew
               {
                   Cats = cats,
                   Food = food
               };
}

Ответ 5

Добавляя к другим ответам, вы можете сделать что-то вроде:

public PewPew SomeMethod(Foo foo)
{
    Task<IList<Cat>> catsTask = GetAllTheCatsAsync(foo);
    Task<IList<Food>> foodTask = GetAllTheFoodAsync(foo);

    // wait for both tasks to complete
    Task.WaitAll(catsTask, foodTask);

    return new PewPew
    {
        Cats = catsTask.Result,
        Food = foodTask.Result
    };
}

public async Task<IList<Cat>> GetAllTheCatsAsync(Foo foo)
{
    await Task.Delay(7000); // wait for a while
    return new List<Cat>();
}

public async Task<IList<Food>> GetAllTheFoodAsync(Foo foo)
{
    await Task.Delay(5000); // wait for a while
    return new List<Food>();
}