异步编程 (async/await)

概述

在现代编程中,异步编程是一个非常重要的概念。它允许程序在等待某些操作(如网络请求或文件读取)完成时,继续执行其他任务,从而提高程序的响应性和效率。C# 通过 async 和 await 关键字提供了强大的异步编程支持。

异步编程的基本概念

同步与异步

  • 同步编程:程序按顺序执行,每个操作必须等待前一个操作完成后才能开始。
  • 异步编程:程序可以在等待某些操作完成的同时,继续执行其他任务。

异步方法的定义

在 C# 中,异步方法通过 async 关键字来定义。异步方法的返回类型通常是 Task 或 Task<T>,其中 T 是方法返回的类型。

public async Task<string> FetchDataAsync()
{
    // 异步操作
    return "Data";
}

await 关键字

await 关键字用于等待一个异步操作完成。它告诉编译器,当前方法需要等待异步操作的结果,但在等待期间,线程可以执行其他任务。

public async Task<string> FetchDataAsync()
{
    var result = await SomeAsyncOperation();
    return result;
}

异步编程的代码示例

示例 1:简单的异步方法

using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        Console.WriteLine("Starting the program...");
        string data = await FetchDataAsync();
        Console.WriteLine($"Data received: {data}");
        Console.WriteLine("Program completed.");
    }

    static async Task<string> FetchDataAsync()
    {
        await Task.Delay(2000); // 模拟一个耗时的操作
        return "Hello, Async World!";
    }
}

示例 2:并行执行多个异步操作

using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        Console.WriteLine("Starting the program...");
        Task<string> task1 = FetchDataAsync("Task 1");
        Task<string> task2 = FetchDataAsync("Task 2");

        string[] results = await Task.WhenAll(task1, task2);

        foreach (var result in results)
        {
            Console.WriteLine($"Data received: {result}");
        }

        Console.WriteLine("Program completed.");
    }

    static async Task<string> FetchDataAsync(string taskName)
    {
        await Task.Delay(2000); // 模拟一个耗时的操作
        return $"Hello from {taskName}!";
    }
}

实践练习

练习 1:异步文件读取

编写一个异步方法,从文件中读取内容并返回。

using System;
using System.IO;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        string content = await ReadFileAsync("example.txt");
        Console.WriteLine(content);
    }

    static async Task<string> ReadFileAsync(string filePath)
    {
        using (StreamReader reader = new StreamReader(filePath))
        {
            return await reader.ReadToEndAsync();
        }
    }
}

练习 2:异步网络请求

编写一个异步方法,从指定的 URL 获取数据并返回。

using System;
using System.Net.Http;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        string url = "https://jsonplaceholder.typicode.com/posts/1";
        string response = await FetchDataFromUrlAsync(url);
        Console.WriteLine(response);
    }

    static async Task<string> FetchDataFromUrlAsync(string url)
    {
        using (HttpClient client = new HttpClient())
        {
            return await client.GetStringAsync(url);
        }
    }
}

总结

异步编程是现代应用程序开发中的一个关键技术,特别是在处理 I/O 密集型操作时。通过使用 async 和 await 关键字,C# 提供了一种简洁且强大的方式来编写异步代码。通过本教程的学习,你应该能够理解异步编程的基本概念,并能够在实际项目中应用这些知识。

进一步学习

  • Task 类:深入了解 Task 类的各种方法和属性,如 Task.WhenAll、Task.WhenAny 等。
  • ConfigureAwait:学习如何使用 ConfigureAwait(false) 来避免上下文切换,提高性能。
  • 异步流:了解 C# 8.0 引入的异步流(IAsyncEnumerable<T>),用于处理异步数据流。

通过这些深入的学习,你将能够更好地掌握异步编程,并在实际项目中发挥其最大潜力。