C# 如何在 .NET 4.5 中“同时”运行这两种方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16728338/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 01:46:20  来源:igfitidea点击:

How can I run both of these methods 'at the same time' in .NET 4.5?

c#.nettaskasync-awaitmultitasking

提问by Pure.Krome

I have a method which does 2 independentpieces of logic. I was hoping I can run them both at the same time.. and only continue afterwards when both those child methods have completed.

我有一个方法可以执行 2 个独立的逻辑部分。我希望我可以运行他们都在同一时间..当这两个孩子的方法完成事后才继续。

I was trying to get my head around the async/awaitsyntax but I just don't get it.

我试图了解async/await语法,但我就是不明白。

Here's the code:

这是代码:

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

So with that code above, I want to say : go and get all the cats and food at the same time. Once we're finished, then return a new PewPew.

所以通过上面的代码,我想说:去同时获取所有的猫和食物。完成后,返回一个新的PewPew.

I'm confused because I'm not sure which classes above are asyncor return a Task, etc. All of em? just the two private ones? I'm also guessing I need to leverage the Task.WaitAll(tasks)method, but I'm unsure how to setupthe tasks to run at the same time.

我很困惑,因为我不确定上面的哪些类是async或返回 aTask等。所有这些类?只有两个私人的?我也在猜测我需要利用该Task.WaitAll(tasks)方法,但我不确定如何设置任务以同时运行。

Suggestions, kind folks?

好心人给点建议?

采纳答案by YK1

Here is what you may want to do:

以下是您可能想要执行的操作:

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

There are two things you need to understand here:

这里有两件事你需要理解:

1) What is diff between this:

1)这之间有什么区别:

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

And this:

和这个:

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

Both will give you similar result in the sense let the 2 asynctasks finish and then return new PewPew- however, difference is that Task.WaitAll()will block the current thread (if that is UI thread, then UI will freeze). instead, awaitwill break down the SomeMethodsay in a state machine, and return from the SomeMethodto its caller as it encounters awaitkeyword. It will not block the thread. The Code below awaitwill be scheduled to run when asynctask is over.

两者都会给你类似的结果,让 2 个async任务完成,然后return new PewPew- 但是,不同之处在于Task.WaitAll()会阻塞当前线程(如果那是 UI 线程,则 UI 将冻结)。相反,awaitSomeMethod在状态机中分解say,并在SomeMethod遇到await关键字时从 the 返回给它的调用者。它不会阻塞线程。下面的代码await将被安排在async任务结束时运行。

2) You could also do this:

2)你也可以这样做:

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

However, this will not start the asynctasks simultaneously. Second task will start after the first is over. This is because how the awaitkeyword works, hope that helps...

但是,这不会async同时启动任务。第一个任务结束后将开始第二个任务。这是因为await关键字的工作原理,希望对您有所帮助...

EDIT: How to use SomeMethod- somewhere at the start of the call tree, you have to use Wait()or Resultproperty - OR - you have to awaitfrom async void. Generally, async voidwould be an event handler:

编辑:如何使用SomeMethod- 在调用树开头的某处,您必须使用Wait()Result属性 - 或者 - 您必须awaitasync void. 通常,async void将是一个事件处理程序:

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

If not then use Resultproperty.

如果没有,则使用Result属性。

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

   return GetFoo2(p);
}

回答by Adam Tal

You don't have to use async if you're not in an async method or you're using an older version of the .Net framework.. just use Tasksfor simplicity:

如果您不在异步方法中或者您使用的是旧版本的 .Net 框架,则不必使用 async ..为了简单起见,只需使用Tasks

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

回答by Maarten

You can use the TPLto wait for multiple tasks while they are running. See here.

您可以使用TPL来等待多个正在运行的任务。见这里

Like this:

像这样:

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

回答by Dimitar Dimitrov

Adding to the other answers, you could do something like:

添加到其他答案,您可以执行以下操作:

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

回答by Matthew Watson

By far the easiest way to do this is to use Parallel.Invoke()

到目前为止,最简单的方法是使用 Parallel.Invoke()

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

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

Parallel.Invoke()will wait for all the methods to return before it itself returns.

Parallel.Invoke()在它自己返回之前将等待所有方法返回。

More information here: http://msdn.microsoft.com/en-us/library/dd460705.aspx

更多信息:http: //msdn.microsoft.com/en-us/library/dd460705.aspx

Note that Parallel.Invoke()handles scaling to the number of processors in your system, but that only really matters if you're starting more than just a couple of tasks.

请注意,Parallel.Invoke()处理扩展到您系统中的处理器数量,但只有当您开始的不仅仅是几个任务时,这才是真正重要的。