我有一个方法可以执行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
等等。所有的em?只是两个私人的?我也猜测我需要利用Task.WaitAll(tasks)
方法,但我不确定如何设置同时运行的任务。
建议,善良的人?
答案 0 :(得分:50)
以下是您可能想要做的事情:
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()
将阻止当前线程(如果是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
关键字的工作原理,希望有帮助...
编辑:如何使用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);
}
答案 1 :(得分:19)
到目前为止,最简单的方法是使用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()
处理扩展到系统中处理器的数量,但只有在您开始的工作不仅仅是几项任务时才真正重要。
答案 2 :(得分:10)
如果您不使用异步方法或使用旧版本的.Net框架,则不必使用async。为简单起见,只需使用任务:
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
答案 3 :(得分:0)
像这样:
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
};
}
答案 4 :(得分:0)
添加其他答案,您可以执行以下操作:
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>();
}