[未知动作时如何等待Task.Run(action)

问题描述 投票:0回答:1

我有以下代码:

  static void Main(string[] args)
    {
        Run(() => LongProcess()).ContinueWith( t => Run(() => LongerProcess()));

        int count = 5;
        do
        {
            Console.WriteLine(count.ToString());
            Thread.Sleep(100);
            count++;
        } while (count < 20);

        Console.ReadKey();
    }

    private static void LongProcess()
    {

        Console.WriteLine("Long Process 1");
        Thread.Sleep(2000);
        Console.WriteLine("Long Process 2");
    }

    private static void LongerProcess()
    {
        Console.WriteLine("Longer Process 1");
        Thread.Sleep(3000);
        Console.WriteLine("Longer Process 2");
    }

    private static async Task Run(Action action)
    {

        await Task.Run(action);  //shouldn't this wait until the action is completed??
                                // how should I modify the code so that the program waits until action is done before returning?

    }

[使用await Task.Run(action);,我希望程序继续进行到action完成之后,再继续下一步。换句话说,我期望输出如下:

Long Process 1
Long Process 2
Longer Process 1
Longer Process 2
5
6
7
8
...
19

但是,输出类似于

Long Process 1
5
6
7
8
...
19
Long Process 2
Longer Process 1
Longer Process 2

问题:

  1. 为什么await Task.Run不等到action完成?
  2. 如何更改代码,使其提供所需的输出?
c# task-parallel-library
1个回答
1
投票

使用await不会等待,这就是重点。如果要等待,请使用Task.Wait

但是,async方法的执行将仅在等待的任务完成后才继续执行(是连续的)。让我们看看您的async方法:

private static async Task Run(Action action)
{

    await Task.Run(action);
    // There is nothing here
}

任务完成后没有任何代码可以执行...好吧,async方法返回一个任务完成时完成的任务。让我们看看您是否await ...

Run(() => LongProcess()).ContinueWith( t => Run(() => LongerProcess()));

你不知道。您解雇该任务,然后就忘了。


我认为这是您想要的:

static async void Main(string[] args)
{
    await Run(() => LongProcess());
    await Run(() => LongerProcess());

    int count = 5;
    do
    {
        Console.WriteLine(count.ToString());
        Thread.Sleep(100);
        count++;
    } while (count < 20);

    Console.ReadKey();
}

Note:异步Main是C#7.1的功能。

此代码将运行调用LongProcess的任务,然后作为运行LongerProcess的任务的延续,然后作为其余代码的延续。

为什么要这样,而不仅仅是同步调用这些方法,这超出了我的范围。

顺便说一句,在async方法中,可以使用await Task.Delay(milliseconds)代替Thread.Sleep(milliseconds)。好处是线程不等待。 它就像在单个执行计时器上继续执行。


如果async/await只是延续,您可能想知道为什么人们要使用它们而不是ContinueWith

让我给您几个理由:

  • async/await的代码更易于阅读。更少的嵌套东西使代码模糊。您可以独立于了解线程而了解代码的功能。
  • async/await的代码更容易编写。您只需编写它就好像它们都是同步的一样,就在其中闪烁了一些asyncawait。您可以编写同步代码,然后担心如何使其并发。您最终也减少了写作,这意味着您效率更高。
  • async/await的代码更智能™。编译器将您的代码重写为连续状态机,使您可以将await放入语句中而无需任何代码Gymnastics™。这扩展到异常处理。您会发现,在继续执行任务并忘记执行任务时,您没有处理异常。如果LongerProcess抛出该怎么办?好吧,有了async/await,您只需将await放在try ... catch的内部,即可完成正确的操作™。

这完全是关注点分离。


您还可能想知道在什么情况下使用async/await而不是同步代码是个好主意。答案是,在处理I / O操作时会发光。与外部系统进行交互时,通常不会立即做出响应。例如,如果要从磁盘读取或从网络下载。

实际上,如果您考虑处理表单并将其事件处理为I / O绑定操作(因为它们是)。您会发现它们是使用async/await的好地方。特别是考虑到UI线程的同步上下文默认情况下将在同一线程上保持连续性。当然,您可以通过使用async/awaitTask.Run与CPU绑定在一起使用。什么时候是个好主意?嗯,是的,当您想保持UI响应速度时。

© www.soinside.com 2019 - 2024. All rights reserved.