关于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;
}
相关推荐
geovindu6 分钟前
java: Task Scheduler
java·开发语言·后端
神奇小梵10 分钟前
java的特殊语法点,与常规语言相异的点
java·开发语言
bnmoel25 分钟前
C++ 基础入门篇(二):引用
开发语言·c++·引用·底层
XiaoZhenHua9835 分钟前
C# WinForms + 西门子S7 + SQLite + EPPlus生产数据采集系统架构设计
系统架构·sqlite·c#
影视飓风TIM1 小时前
C++ 智能指针:auto_ptr / unique_ptr / shared_ptr / weak_ptr 原理与使用
开发语言·c++
一木 之林1 小时前
李沐《动手学深度学习》知识卡合集:从 Softmax 回归到房价实战(第24-50集)
开发语言·c++·人工智能
心中有你02141 小时前
Java Swing实现校园最短路径导航系统(Dijkstra算法完整源码+详细解析)
java·开发语言·算法
Alphapeople1 小时前
路径规划算法的python实现
开发语言·python·算法
重生之小比特1 小时前
【Java SE】数组的定义与使用
java·开发语言
旋生万物1 小时前
圈道裂痕——用 Python 验证素数分布的螺旋生成论判据
开发语言·python·数论·素数·cci·可计算数学