Как я могу запустить оба этих метода "одновременно" 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>();
}