异步编程 #

一、异步编程概述 #

1.1 为什么需要异步 #

  • 避免阻塞UI线程
  • 提高响应性
  • 提高资源利用率

1.2 async/await特点 #

  • 语法简洁
  • 非阻塞
  • 基于Task

二、async关键字 #

2.1 异步方法 #

csharp
public async Task DoWorkAsync()
{
    await Task.Delay(1000);
    Console.WriteLine("工作完成");
}

public async Task<int> CalculateAsync()
{
    await Task.Delay(1000);
    return 42;
}

public async Task<string> GetDataAsync()
{
    await Task.Delay(1000);
    return "数据";
}

2.2 async void #

csharp
public async void FireAndForget()
{
    await Task.Delay(1000);
    Console.WriteLine("完成");
}

private async void Button_Click(object sender, EventArgs e)
{
    await LoadDataAsync();
}

2.3 异步Main #

csharp
public static async Task Main(string[] args)
{
    await DoWorkAsync();
}

三、await关键字 #

3.1 等待Task #

csharp
public async Task ProcessAsync()
{
    await Task.Delay(1000);
    
    Task<int> task = Task.Run(() => Calculate());
    int result = await task;
    
    await Task.WhenAll(task1, task2);
}

3.2 await行为 #

csharp
public async Task ExampleAsync()
{
    Console.WriteLine("开始");
    
    await Task.Delay(1000);
    
    Console.WriteLine("延迟后");
}

3.3 ConfigureAwait #

csharp
public async Task ProcessAsync()
{
    await Task.Delay(1000).ConfigureAwait(false);
    
    string data = await GetDataAsync().ConfigureAwait(false);
}

四、异步模式 #

4.1 Task-based异步模式(TAP) #

csharp
public class DataService
{
    public async Task<string> GetDataAsync()
    {
        await Task.Delay(1000);
        return "数据";
    }
    
    public async Task SaveDataAsync(string data)
    {
        await Task.Delay(1000);
    }
}

4.2 I/O绑定异步 #

csharp
public async Task<string> ReadFileAsync(string path)
{
    using var reader = new StreamReader(path);
    return await reader.ReadToEndAsync();
}

public async Task WriteFileAsync(string path, string content)
{
    await using var writer = new StreamWriter(path);
    await writer.WriteAsync(content);
}

4.3 CPU绑定异步 #

csharp
public async Task<int> CalculateAsync(int n)
{
    return await Task.Run(() =>
    {
        int result = 0;
        for (int i = 0; i < n; i++)
        {
            result += i;
        }
        return result;
    });
}

五、异步流 #

5.1 IAsyncEnumerable #

csharp
public async IAsyncEnumerable<int> GenerateNumbersAsync(int count)
{
    for (int i = 0; i < count; i++)
    {
        await Task.Delay(100);
        yield return i;
    }
}

await foreach (var number in GenerateNumbersAsync(10))
{
    Console.WriteLine(number);
}

5.2 异步迭代器 #

csharp
public async IAsyncEnumerable<string> ReadLinesAsync(string path)
{
    using var reader = new StreamReader(path);
    while (await reader.ReadLineAsync() is string line)
    {
        yield return line;
    }
}

await foreach (var line in ReadLinesAsync("data.txt"))
{
    Console.WriteLine(line);
}

六、ValueTask #

6.1 ValueTask #

csharp
public ValueTask<int> GetValueAsync(bool useCache)
{
    if (useCache && _cachedValue.HasValue)
    {
        return new ValueTask<int>(_cachedValue.Value);
    }
    
    return new ValueTask<int>(FetchValueAsync());
}

private async Task<int> FetchValueAsync()
{
    await Task.Delay(1000);
    _cachedValue = 42;
    return _cachedValue.Value;
}

6.2 ValueTask vs Task #

csharp
public ValueTask<string> GetDataAsync()
{
    if (_cache.TryGetValue(key, out string cached))
    {
        return new ValueTask<string>(cached);
    }
    
    return new ValueTask<string>(FetchFromServerAsync());
}

七、异步最佳实践 #

7.1 避免async void #

csharp
public async Task DoWorkAsync()
{
    await Task.Delay(1000);
}

public async void BadExample()
{
    await Task.Delay(1000);
}

7.2 异步方法命名 #

csharp
public async Task<string> GetDataAsync()
public async Task SaveAsync(string data)
public async Task<bool> ExistsAsync(int id)

7.3 避免同步等待 #

csharp
public async Task GoodExample()
{
    await Task.Delay(1000);
}

public void BadExample()
{
    Task.Delay(1000).Wait();
    Task.Delay(1000).Result;
}

7.4 取消支持 #

csharp
public async Task<string> GetDataAsync(CancellationToken cancellationToken = default)
{
    using var client = new HttpClient();
    return await client.GetStringAsync("https://api.example.com/data", cancellationToken);
}

八、实战示例 #

8.1 异步HTTP客户端 #

csharp
public class ApiClient
{
    private readonly HttpClient _client = new();
    
    public async Task<T?> GetAsync<T>(string url, CancellationToken cancellationToken = default)
    {
        var response = await _client.GetAsync(url, cancellationToken);
        response.EnsureSuccessStatusCode();
        
        var json = await response.Content.ReadAsStringAsync(cancellationToken);
        return JsonSerializer.Deserialize<T>(json);
    }
    
    public async Task PostAsync<T>(string url, T data, CancellationToken cancellationToken = default)
    {
        var json = JsonSerializer.Serialize(data);
        var content = new StringContent(json, Encoding.UTF8, "application/json");
        var response = await _client.PostAsync(url, content, cancellationToken);
        response.EnsureSuccessStatusCode();
    }
}

8.2 异步数据加载 #

csharp
public class DataLoader
{
    public async Task<List<User>> LoadUsersAsync()
    {
        var users = new List<User>();
        
        await foreach (var user in FetchUsersAsync())
        {
            users.Add(user);
        }
        
        return users;
    }
    
    private async IAsyncEnumerable<User> FetchUsersAsync()
    {
        for (int page = 1; ; page++)
        {
            var batch = await FetchPageAsync(page);
            if (batch.Count == 0) yield break;
            
            foreach (var user in batch)
            {
                yield return user;
            }
        }
    }
    
    private async Task<List<User>> FetchPageAsync(int page)
    {
        await Task.Delay(100);
        return new List<User>();
    }
}

九、总结 #

异步编程要点:

要点 说明
async 标记异步方法
await 等待异步操作
Task 异步返回类型
ValueTask 高性能异步
IAsyncEnumerable 异步流

下一步,让我们学习线程同步!

最后更新:2026-03-26