2

完成多种方法后,我需要生成报告。但在此示例中,它们不是异步的。

    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

4 回答 4

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

不幸的是,我们没有展示异步等待的好处,因为我们同时没有做任何事情。

于 2013-07-25T09:07:28.833 回答
2

您的代码有两个问题。

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

第二个问题是您正在开始异步工作,但Main在有机会完成之前又从那里返回。如果这是一个简单的概念验证,那么您可以调用Wait您的顶级任务(通常,您永远不会像我在 MSDN 文章中描述的那样混合阻塞和异步代码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);
}

如果这不仅仅是概念验证,并且您实际上打算创建一个异步控制台应用程序,那么我建议您使用我在博客中描述的单线程async兼容上下文。

于 2013-07-25T11:56:11.520 回答
1

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

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

这会做你想要的。

于 2013-07-25T09:02:49.173 回答
-4

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

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

于 2013-07-25T09:04:35.650 回答