如何异步运行一些方法并捕获它们的末尾
本文关键字:方法 何异步 异步 运行 | 更新日期: 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
关键字。所以没有await
的async
是无用的。正如@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应该能正常工作。