关于C#编程中的async / await关键字

关于C#编程中的async / await关键字


一句话理解

async/await 本质是:用"同步写法"写"异步代码",避免线程被阻塞。


核心

  • async:告诉编译器------这个方法里"可能会停下来等一会儿"
  • await :真的"停下来等",但不占用线程
  • 等待期间:线程被释放,可以去干别的事
  • 等结果好了:自动从 await 后一行继续执行

👉 不是多线程魔法,而是状态机 + 回调的语法糖


最基础示例

csharp 复制代码
static async Task Main()
{
    Console.WriteLine("开始");
    await Task.Delay(2000);   // 模拟耗时操作(2秒)
    Console.WriteLine("结束");
}

执行过程

  1. 打印「开始」
  2. 遇到 await
    → 方法"挂起",线程被释放
  3. 2 秒后恢复执行
  4. 打印「结束」

重点:这 2 秒内,线程没被卡死


对比:同步 vs async

❌ 同步(阻塞线程)

csharp 复制代码
Thread.Sleep(2000); // 线程被卡住

✅ 异步(不阻塞)

csharp 复制代码
await Task.Delay(2000); // 线程释放

模拟真实场景示例

csharp 复制代码
async Task<string> DownloadAsync()
{
    using var client = new HttpClient();
    return await client.GetStringAsync("https://example.com");
}

调用:

csharp 复制代码
string html = await DownloadAsync();

你看到的是同步写法

底层其实是 异步 + 回调 + 状态机


async / await 的 3 条铁律

  1. await 只能等 Task / Task
  2. async 方法几乎都返回 Task
  3. 一路 async,就一路 await(不要中途 .Result

最容易踩的坑 ❌

csharp 复制代码
var result = DownloadAsync().Result; // ❌ 可能死锁

✅ 正确写法:

csharp 复制代码
var result = await DownloadAsync();

一句话总结

async/await 不是让代码更快,而是让程序不卡

特别适合:UI、IO、网络、数据库、上位机通信

用 .NET Framework 4.8 + WPF(.NET Framework 4.8)

核心目的就一个:直观看到"同步会卡 UI,async/await 不会"。

WPF 示例(.NET Framework 4.8)

XAML(MainWindow.xaml)

xml 复制代码
<Window x:Class="WpfAsyncDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Async Demo" Height="200" Width="360">
    <Grid Margin="12">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <StackPanel Orientation="Horizontal" Margin="0,0,0,12">
            <Button Width="120" Margin="0,0,12,0" Content="同步卡死" Click="BtnSync_Click"/>
            <Button Width="120" Content="Async不阻塞" Click="BtnAsync_Click"/>
        </StackPanel>

        <TextBlock Grid.Row="1" FontSize="16" Text="{Binding Status}" />
    </Grid>
</Window>

代码(MainWindow.xaml.cs)

csharp 复制代码
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace WpfAsyncDemo
{
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        private string _status = "状态";
        public string Status
        {
            get => _status;
            set { _status = value; OnPropertyChanged(); }
        }

        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
        }

        // ❌ 同步:阻塞UI线程,窗口假死
        private void BtnSync_Click(object sender, RoutedEventArgs e)
        {
            Status = "同步开始(UI将卡住3秒)";
            Thread.Sleep(3000);
            Status = "同步结束";
        }

        // ✅ 异步:不阻塞UI线程
        private async void BtnAsync_Click(object sender, RoutedEventArgs e)
        {
            Status = "异步开始(UI仍然流畅)";
            await Task.Delay(3000);
            Status = "异步结束";
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string name = null)
            => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }
}

关键点

  • WPF 的按钮点击事件都在 UI线程
  • Thread.Sleep / 同步IO 会把 UI线程卡住 → 窗口假死
  • await Task.Delay/await IO让出 UI线程 → 窗口继续响应
  • 默认情况下:await 之后会回到 UI线程(所以你可以直接更新 Label/TextBlock,不用 Invoke)

进阶:模拟"真实耗时IO/计算"

你如果要做"上位机通信/数据库/文件",通常是:

  • IO:直接 await(比如 HttpClient、Stream.ReadAsync、SqlCommand.ExecuteReaderAsync)
  • CPU计算:用 Task.Run 扔到线程池

给你一个通用模板(WinForms/WPF 都能用):

csharp 复制代码
private async void BtnWork_Click(object sender, EventArgs e)
{
    Status = "开始干活...";
    var result = await Task.Run(() =>
    {
        // CPU密集:放这里
        Thread.Sleep(3000);
        return "完成";
    });
    Status = result;
}
相关推荐
小六子成长记17 小时前
【C++】:多态的实现
开发语言·c++
好好学操作系统17 小时前
flash_attn ImportError undefined symbol:
开发语言·python
CCPC不拿奖不改名17 小时前
面向对象编程:继承与多态+面试习题
开发语言·数据结构·python·学习·面试·职场和发展
꧁Q༒ོγ꧂17 小时前
算法详解(一)--算法系列开篇:什么是算法?
开发语言·c++·算法
m5655bj17 小时前
使用 C# 将 RTF 文档转换为 PDF 格式
pdf·c#
星火开发设计17 小时前
Python数元组完全指南:从基础到实战
开发语言·windows·python·学习·知识·tuple
wuk99817 小时前
栅格障碍物地图生成与机器人路径规划MATLAB程序
开发语言·matlab
郝学胜-神的一滴17 小时前
深入浅出:Python类变量与实例变量的核心差异与应用实践
开发语言·python·程序人生
froginwe1117 小时前
C 未定义行为
开发语言