← SEARCHABLE ARCHIVE
C# · 2026-08-07

从 C# 基础到掌握 — 第 8 集

使用async和await构建异步任务

INTERACTIVE READING MODE →

该博客上撰写的文章是出于教学目的而创建的。 另外,文章中的信息可能不正确,请谨慎。

在等待网络或文件操作时阻塞线程也可能冻结屏幕和其他操作。 async 和await 表示等待任务,以便可以连续执行。

返回任务

async Task<PlayerData> LoadPlayerAsync(
    string url,
    CancellationToken cancellationToken)
{
    using HttpResponseMessage response =
        await httpClient.GetAsync(url, cancellationToken);

    response.EnsureSuccessStatusCode();

    PlayerData? data = await response.Content
        .ReadFromJsonAsync<PlayerData>(cancellationToken);

    return data ?? throw new InvalidDataException("Player data is empty");
}

当您遇到等待时,您可以稍后继续执行其余代码,而不是保留当前线程直到任务完成。 异步方法基本上返回一个任务,以便调用者可以观察完成和失败。

取消转发

using var source = new CancellationTokenSource(TimeSpan.FromSeconds(5));

try
{
    PlayerData data = await LoadPlayerAsync(url, source.Token);
}
catch (OperationCanceledException)
{
    Console.WriteLine("Loading canceled");
}

Cancel 不是强制终止线程的函数。 请求任务验证令牌并在安全点中止的合约。

等待多个任务

Task<ItemData> itemTask = LoadItemsAsync(token);
Task<QuestData> questTask = LoadQuestsAsync(token);

await Task.WhenAll(itemTask, questTask);

ItemData items = await itemTask;
QuestData quests = await questTask;

相互不依赖的等待任务可以先启动,然后一起等待。 简单地将 CPU 计算标记为异步并不会自动使其成为并行计算。

避免流动

使用Task的.Result或.Wait()进行同步等待可能会阻塞线程或创建死锁,具体取决于执行环境。 最好尽可能继续异步调用路径。

除事件处理程序外,应避免使用 async void,因为调用者无法等待完成和异常。 异步代码的关键不是添加关键字,而是向调用者传达完成、失败和取消的流程。