关于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;
}
相关推荐
朝朝辞暮i5 小时前
C++ 第 23 课:class —— 开始真正进入面向对象
开发语言·c++·算法
小师兄吃牛肉6 小时前
C语言篇:宏
c语言·开发语言
郑同学的笔记6 小时前
【c++随笔28】strcmp 和 memcmp对比
开发语言·c++
未来之窗软件服务6 小时前
C# 截图源码支持自动保存-东方仙盟
c#·仙盟创梦ide·东方仙盟·电脑工具
言乐67 小时前
Python根据无法识别搜索词找出可能输入内容模型
开发语言·python·django·virtualenv·pygame
weixin_307779137 小时前
有限产能智能排产与动态重排智能体:从需求解构到技术实现
开发语言·人工智能·算法·架构
kakakahahahaha7 小时前
Windows C盘临时文件清理:%temp%、Windows Temp、Prefetch、Windows.old与hiberfil.sys处理指南
c语言·开发语言·windows
朝朝辞暮i7 小时前
C++ 第 27 课:智能指针 shared_ptr
开发语言·c++·算法
朝朝辞暮i7 小时前
C++ 第 29 课:回调函数 Callback
开发语言·c++·算法
笨笨饿7 小时前
140_AI新手村MCP与Skills是干嘛的
开发语言·人工智能·python·stm32·单片机·嵌入式硬件·物联网