[英]C# async/await in a console application
我想在 C# 控制台应用程序中测试 async 和 await,所以我编写了这个测试代码。 当我在 Winforms 应用程序中使用 async/await 时,例如:在 ButtonClicked 事件处理函数中调用这个 doSth。 它会在另一个线程中延迟 3000 毫秒,并在 MainThread 中输出“doSth execute finished”。 但是在这个控制台应用程序中,它在工作线程中输出“doSth execute finished”,为什么?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp12
{
class Program
{
static void Main(string[] args)
{
doSth();
Console.WriteLine("doSth call finished.");
Thread.Sleep(5000);
Console.WriteLine("Main finished.");
}
private static async void doSth()
{
Console.WriteLine("doSth execute Started...");
await Task.Delay(3000);
Console.WriteLine("doSth execute finished.");
}
}
}
这是 Winforms 应用程序中的测试代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp4
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
doSth();
Console.WriteLine("doSth call finished.");
Thread.Sleep(5000);
Console.WriteLine("Main finished.");
}
private static async void doSth()
{
Console.WriteLine("doSth execute Started...");
await Task.Delay(3000);
Console.WriteLine("doSth execute finished.");
}
}
}
doSth execute Started...
doSth call finished.
doSth execute finished.
Main finished.
请按任意键继续. . .
doSth execute finished.
doSth execute Started...
doSth call finished.
Main finished.
如果我删除 Thread.Sleep(5000) 并使主线程不休眠,并且在控制台应用程序中,它将丢失输出并且不会调用 doSth 函数的第二个输出。 在 Winforms 应用程序中,没有效果。
首先,async/await 并不意味着会有其他线程在执行。 如果 await 操作符被命中,那么那段代码的执行就会停在那里(并等待),而在这个操作等待的同时,同一个线程可以接受更多的工作(更多的任务要做)。
因此,异步代码是尽可能多地重用相同的线程,而不是跨越尽可能多的线程执行代码。
删除Thread.Sleep
您只需完成工作即可。 您刚刚完成运行应用程序,而后台的任务仍在运行。 但它已因您的应用程序而终止。
最终,无论async void
您键入async void
,您都可能犯了一个错误(对 winform 上的事件处理程序稍加注意); 这里的解决方法是等待(如果您唯一的非后台线程,即Main
入口点,退出:然后控制台应用程序终止):
static async Task Main(string[] args)
{
await doSthAsync();
// ...
}
private static async Task doSthAsync() {...}
请注意,异步和并发/并行是非常不同的事情; 如果您的意图是实现并发,那么也许:
static async Task Main(string[] args)
{
var pending = Task.Run(doSthAsync);
// ...
await pending; // to allow parallel work to finish
}
其他答案解释了为什么Thread.Sleep
使应用程序保持活动状态,直到您可以看到所有输出。
我来回答你的第一个问题:
在 ButtonClicked 事件处理函数中调用此 doSth。 它会在另一个线程中延迟 3000 毫秒,并在 MainThread 中输出“doSth execute finished”。 但是在这个控制台应用程序中,它在工作线程中输出“doSth execute finished”,为什么?
旁注:延迟不是“在另一个线程中”完成的。 这只是一个计时器。
线程不同的原因是 UI 应用程序具有“上下文”。 这个“上下文”由await
捕获并用于恢复执行async
方法(正如我在我的博客中所描述的那样)。 UI 应用程序中的 UI 上下文将继续在主 UI 线程上执行async
方法。 相比之下,控制台应用程序没有“上下文”,因此async
方法会在线程池线程上恢复执行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.