跳到主要内容

C# 并发模式

介绍

在现代应用程序开发中,并发是一个非常重要的概念。它允许程序同时执行多个任务,从而提高性能和响应能力。C# 提供了多种并发模式,帮助开发者有效地管理多线程和异步操作。本文将介绍 C# 中常见的并发模式,并通过代码示例和实际案例帮助你理解这些概念。

什么是并发模式?

并发模式是指在多线程或异步编程中,用于管理任务执行和资源共享的设计模式。C# 提供了多种并发模式,包括:

  1. 异步编程模型(APM)
  2. 基于事件的异步模式(EAP)
  3. 任务并行库(TPL)
  4. 异步/等待模式(async/await)

接下来,我们将逐一介绍这些模式。


1. 异步编程模型(APM)

异步编程模型(Asynchronous Programming Model,APM)是 C# 早期的一种并发模式。它使用 BeginXXXEndXXX 方法来启动和结束异步操作。

示例代码

csharp
using System;
using System.IO;

class Program
{
static void Main()
{
byte[] buffer = new byte[100];
FileStream fs = new FileStream("example.txt", FileMode.Open, FileAccess.Read, FileShare.Read, 1024, FileOptions.Asynchronous);

IAsyncResult result = fs.BeginRead(buffer, 0, buffer.Length, null, null);

// 模拟其他工作
Console.WriteLine("正在执行其他任务...");

int bytesRead = fs.EndRead(result);
fs.Close();

Console.WriteLine($"读取了 {bytesRead} 字节的数据。");
}
}

输出

正在执行其他任务...
读取了 100 字节的数据。
备注

APM 模式在现代 C# 开发中已逐渐被淘汰,推荐使用 async/await 模式。


2. 基于事件的异步模式(EAP)

基于事件的异步模式(Event-based Asynchronous Pattern,EAP)通过事件来通知异步操作的完成。它通常与 BackgroundWorker 类一起使用。

示例代码

csharp
using System;
using System.ComponentModel;

class Program
{
static void Main()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += Worker_DoWork;
worker.RunWorkerCompleted += Worker_RunWorkerCompleted;

worker.RunWorkerAsync();

Console.WriteLine("主线程继续执行其他任务...");
}

private static void Worker_DoWork(object sender, DoWorkEventArgs e)
{
// 模拟耗时操作
System.Threading.Thread.Sleep(2000);
e.Result = "任务完成";
}

private static void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine(e.Result);
}
}

输出

主线程继续执行其他任务...
任务完成
提示

EAP 模式适合需要与 UI 交互的场景,因为它可以避免阻塞主线程。


3. 任务并行库(TPL)

任务并行库(Task Parallel Library,TPL)是 .NET 提供的一个强大的并发编程框架。它基于 TaskTask<TResult> 类,简化了多线程编程。

示例代码

csharp
using System;
using System.Threading.Tasks;

class Program
{
static async Task Main()
{
Task<int> task = Task.Run(() => CalculateSum(100));

Console.WriteLine("正在执行其他任务...");

int result = await task;
Console.WriteLine($"计算结果: {result}");
}

static int CalculateSum(int n)
{
int sum = 0;
for (int i = 1; i <= n; i++)
{
sum += i;
}
return sum;
}
}

输出

正在执行其他任务...
计算结果: 5050
警告

TPL 适合 CPU 密集型任务,但需要注意线程池的资源管理。


4. 异步/等待模式(async/await)

async/await 是 C# 中最常用的并发模式。它通过 asyncawait 关键字简化了异步编程。

示例代码

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

class Program
{
static async Task Main()
{
Console.WriteLine("开始下载...");
string content = await DownloadContentAsync("https://example.com");
Console.WriteLine($"下载完成,内容长度: {content.Length}");
}

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

输出

开始下载...
下载完成,内容长度: 1256
注意

async/await 适合 I/O 密集型任务,但需要避免阻塞调用。


实际案例:并发下载器

以下是一个使用 async/await 实现并发下载器的示例:

csharp
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;

class Program
{
static async Task Main()
{
List<string> urls = new List<string>
{
"https://example.com",
"https://example.org",
"https://example.net"
};

List<Task<string>> downloadTasks = new List<Task<string>>();
foreach (var url in urls)
{
downloadTasks.Add(DownloadContentAsync(url));
}

string[] contents = await Task.WhenAll(downloadTasks);
Console.WriteLine("所有下载任务完成!");
}

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

总结

C# 提供了多种并发模式,每种模式都有其适用的场景。以下是选择并发模式的建议:

  • APM:已过时,不推荐使用。
  • EAP:适合与 UI 交互的场景。
  • TPL:适合 CPU 密集型任务。
  • async/await:适合 I/O 密集型任务。

通过合理选择并发模式,可以显著提高应用程序的性能和响应能力。


附加资源


练习

  1. 使用 async/await 实现一个并发文件下载器。
  2. 尝试将 TPL 与 async/await 结合,实现一个并行计算器。
  3. 研究 BackgroundWorker 类,并实现一个简单的进度条功能。

祝你学习愉快!