【问题标题】:Why the main does not wait until the async method has finished?为什么 main 不等到异步方法完成?
【发布时间】:2015-12-01 15:09:36
【问题描述】:

我有这个控制台应用程序,我的应用程序的一个 reduce 示例,但它允许重现行为。

class Program
{
    static void Main(string[] args)
    {
        try
        {
            Console.WriteLine("Start");
            addAsync01(1, 2);
        }
        catch
        {
        }
        finally
        {
            Console.WriteLine("Finally");
            Console.ReadKey();
        }
        addAsync01(1,2);
    }

    private static async void addAsync01(int sum1, int sum2)
    {
        int result = await AddAsync(sum1, sum2);
        Console.WriteLine("El resultado de sumar 1 y 2 es: " + result);
    }

    public static async Task<int> AddAsync(int num1, int num2)
    {
        return await Task<int>.Run(() =>
        {
            return num1 + num2;
        });
    }
}

addSyn01方法中,我使用了await关键字,但是应用程序并没有等到AddAsync方法完成,继续运行,所以我在控制台中得到的结果是:

Start
Finally
El resultado de sumar 1 y 2 es: 3

我预料到了:

Start
El resultado de sumar 1 y 2 es: 3
Finally

如果我没记错的话,await 关键字等待async 方法完成继续下一行代码。

如果我在 AddAsync01 方法中使用此代码,它会按预期工作:

private static async void addAsync01(int sum1, int sum2)
{
    Task<int> tskResult = AddAsync(1, 2);
    await Task.WhenAll(tskResult);

    Console.WriteLine("El resultado de sumar 1 y 2 es: " + tskResult.Result);
}

【问题讨论】:

  • 你也需要await addAsync01
  • 其实首先需要将addAsync01重新定义为Task而不是voidasync void 通常不好,除了事件处理程序。
  • async void 方法是一劳永逸的。你得到关于他们的进展或结果的信息。所以不可能等待他们。不要使用async void 方法。
  • @GlorinOakenfoot 你将无法等待Main
  • @Jonesopolis 是的。正如下面的答案所示,您必须使用 .Wait/Result 的恼人情况之一。

标签: c# async-await task-parallel-library


【解决方案1】:

控制台应用程序不支持应用程序入口点上的async / await,正如您所期望的那样。您需要调用 .Wait() 或(.Result for Task&lt;T&gt; 返回方法)。如果您对为什么它不能按预期工作感到好奇,我建议您查看 Stephen Cleary's Async Console Program

class Program
{
    static void Main(string[] args)
    {
        try
        {
            Console.WriteLine("Start");

            addAsync01(1, 2).Wait();
        }
        catch
        {
            //TODO
        }
        finally
        {
            Console.WriteLine("Finally");
            Console.ReadKey();
        }
        addAsync01(1, 2).Wait();
    }

    static async Task addAsync01(int sum1, int sum2)
    {
        int result = await AddAsync(sum1, sum2);
        Console.WriteLine("El resultado de sumar 1 y 2 es: " + result);
    }

    public static async Task<int> AddAsync(int num1, int num2)
    {
        return await Task.Run(() => num1 + num2);
    }
}

另外,您需要在addAsync01 方法上返回Task

这是更改后的输出:

Start
El resultado de sumar 1 y 2 es: 3
Finally

虽然此更改确实有效并正确回答了您的问题,但对我来说很奇怪,您想在没有明显原因的情况下引入异步代码。如果您只是想了解它的功能,那很好;但是,如果这是理想的代码,您可能需要重新考虑该方法。两个int's 的总和在计算上一点也不昂贵,而且这可以更快地同步完成并且开销更少。

【讨论】:

  • 谢谢大卫。真正用于测试,因为真正的方法不是求和,是使用实体框架中的异步方法的方法。真的,我已经将 await 与异步 EF 方法一起使用,并且按预期工作,但在这种情况下不是,我想知道原因。在我的实际应用程序中,它是一个库项目,而不是控制台应用程序。
  • 很高兴我能帮上忙!在您的类库中,您应该使用 async / await。 async 关键字让方法使用 await 关键字,await 关键字基本上会暂停方法调用并在异步方法产生结果(或从执行返回)时返回。这是处理 Task 和 Task. 的理想方式
【解决方案2】:

如果您希望 addAsync01() 方法是同步的,请不要将其声明为异步。当不将该方法声明为异步时,您将无法在其中使用“等待”。因此,您必须通过以下方式显式等待从同步方法调用的异步方法:

    private static void addAsync01(int sum1, int sum2)
    {
        var lTask = AddAsync(sum1, sum2);
        lTask.Wait();
        int result = lTask.Result;

        Console.WriteLine("El resultado de sumar 1 y 2 es: " + result);
    }

在复杂的多线程环境中使用此类代码时要小心。很容易产生死锁。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-01-27
    • 2019-10-19
    • 2014-08-09
    • 2013-08-19
    • 1970-01-01
    • 1970-01-01
    • 2021-06-27
    • 1970-01-01
    相关资源
    最近更新 更多