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

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

Я пытался разобраться в 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, etc. Все? только два частных? Я также предполагаю, что мне нужно использовать Task.WaitAll(tasks) метод, но я не уверен, как настройка задачи для запуска в то же время.

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

5 ответов


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

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) в чем разница между этим:

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

и так:

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

оба дадут вам аналогичный результат в том смысле, что пусть 2 async задачи заканчиваются, а затем return new PewPew - однако разница в том, что Task.WaitAll() заблокирует текущий поток (если это поток пользовательского интерфейса, то пользовательский интерфейс замерзнет). вместо 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);
}

безусловно, самый простой способ сделать это-использовать 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() обрабатывает масштабирование до количества процессоров в вашей системе, но это действительно имеет значение, только если вы начинаете больше, чем просто пару задач.


вам не нужно использовать 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

можно использовать 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
               };
}

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

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>();
}