如何异步运行一些方法并捕获它们的末尾

本文关键字:方法 何异步 异步 运行 | 更新日期: 2023-09-27 18:25:02

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

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

如何使它们真正异步?

如何异步运行一些方法并捕获它们的末尾

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

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

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

您的代码有两个问题。

首先,正如其他人所指出的,async并不意味着"在后台线程上运行"。async所做的只是启用一个编译器生成的状态机来处理await关键字。所以没有awaitasync是无用的。正如@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兼容上下文,正如我在博客中所描述的那样。

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

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

这会做你想做的事。

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

你的console.writeline应该能正常工作。