如何运行某些方法异步并捕获它们的结尾?

时间:2013-07-25 08:58:12

标签: c# async-await

一旦完成了许多方法,我需要生成报告。但在这个示例中,它们不是异步的。

    static void Main(string[] args)
    {
        TaskMan();
    }

    async static void TaskMan()
    {
        Task t1 = m1();
        Task t2 = m2();
        await Task.WhenAll(t1, t2);
        Console.WriteLine("Complete");
    }

    async static Task m1()
    {
        decimal result = 0;
        for (int n = 1; n < 100000000; n++)
        {
            result += n;
        }
        Console.WriteLine(result);
    }

    async static Task m2()
    {
        decimal result = 0;
        for (int n = 1; n < 100000000; n++)
        {
            result += n;
        }
        Console.WriteLine(result);
    }

如何真正实现异步?

4 个答案:

答案 0 :(得分:5)

首先,它不是异步运行的,因为在这些行中你实际上是以非异步方式调用方法:

Task t1 = m1();
Task t2 = m2();

这是因为你既没有等待此时的电话,也没有在内部等待。净效应是标准方法调用。

其次,async并不一定意味着在另一个线程上。

以下修订将启动新任务并将它们与您可用于监控其完成的承诺相关联,然后以异步方式与WhenAll一样。请注意,该任务将从StartNew开始,而不是WhenAll

async static void TaskMan()
{
    Task t1 = Task.Run((Action)m1);
    Task t2 = Task.Run((Action)m2);

    await Task.WhenAll(t1, t2);
    Console.WriteLine("Compete");
}

static void m1()
{
    decimal result = 0;
    for (int n = 1; n < 100000000; n++)
    {
        result += n;
    }
    Console.WriteLine(result);
}

static void m2()
{
    decimal result = 0;
    for (int n = 1; n < 100000000; n++)
    {
        result += n;
    }
    Console.WriteLine(result);
}

不幸的是,我们没有证明异步等待的好处,因为我们没有做任何事情。

答案 1 :(得分:2)

您的代码存在两个问题。

首先,正如其他人所指出的那样,async并不意味着“在后台线程上运行”。 async所做的就是启用编译器生成的状态机来处理await关键字。因此async没有await是没用的。正如@svick指出的那样,不要忽略编译器警告!我的博客上有async intro你可能会觉得有帮助。您应该使用Task.Run将工作明确地放在后台线程上。

第二个问题是你正在开始异步工作,但是在给它机会完成之前从Main返回。如果这是一个简单的概念验证,那么您可以在顶级任务上调用Wait(正如我在MSDN文章中描述的那样never want to mix blocking and asynchronous code like this,但是Main控制台应用程序的方法是该规则的一个例外)。

static void Main(string[] args)
{
    TaskManAsync().Wait();
}

static async Task TaskManAsync()
{
    Task t1 = Task.Run(() => m1());
    Task t2 = Task.Run(() => m2());
    await Task.WhenAll(t1, t2);
    Console.WriteLine("Complete");
}

static void m1()
{
    decimal result = 0;
    for (int n = 1; n < 100000000; n++)
    {
        result += n;
    }
    Console.WriteLine(result);
}

static void m2()
{
    decimal result = 0;
    for (int n = 1; n < 100000000; n++)
    {
        result += n;
    }
    Console.WriteLine(result);
}

如果这不仅仅是一个概念验证,而您实际上打算创建一个异步控制台应用程序,那么我建议您use a single-threaded async-compatible context,就像我在博客中描述的那样。

答案 2 :(得分:1)

async关键字并不意味着该方法将以异步方式运行。我相信你对这些方法有VS报告警告,因为他们没有等待。要在线程中运行,您应该写:

return Task.Factory.StartNew(()=>
    decimal result = 0;
    for (int n = 1; n < 100000000; n++)
    {
        result += n;
    }
    Console.WriteLine(result);
});

这将做你想要的。

答案 3 :(得分:-4)

使用线程并为每个函数创建一个单独的线程。线程完成后,您可以收到通知。请注意,您无法从线程中调用的函数更新UI。您必须使用其他方法从线程更新UI本身,这可能是一个新问题。

你的console.writeline应该可以工作。