C# 并发与多线程:进阶篇

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

C# 并发与多线程:进阶篇



在现代 C# 开发中,并发与多线程不仅仅是扩展能力,更是构建快速、响应灵敏且可扩展应用程序的基础工具。在进阶层面,我们超越了简单的 Task.Run 调用,需要面对调度器的细微之处、上下文同步以及处理共享数据的模式。本文将深入剖析 C# (.NET) 中关键的进阶并发概念,帮助您编写高效且安全的代码。



1. Task 与 ValueTask:深入使用



Task 类是 C# 异步编程的基础。然而,在进阶层面,理解 Task 与 ValueTask 的区别以及管理任务的生命周期至关重要。



何时使用 ValueTask?

ValueTask 是一种结构体,当结果已同步可用时,可以避免为 Task 对象分配内存。这对于高性能场景(例如缓存方法)至关重要。



public class CacheService{    private readonly Dictionary<string, string> _cache = new();

public async ValueTask<string> GetDataAsync(string key) { if (_cache.TryGetValue(key, out string value)) { // 结果已存在,不创建 Task return value; }

// 异步获取数据 string data = await FetchFromDatabaseAsync(key); _cache[key] = data; return data; }

private async Task<string> FetchFromDatabaseAsync(string key) { await Task.Delay(100); // 模拟延迟 return $"Data for {key}"; }}


进阶错误处理与取消

使用 CancellationToken 正确取消长时间运行的操作。通过 CancellationTokenSource.CreateLinkedTokenSource 组合多个令牌。



public async Task ProcessWithTimeoutAsync(CancellationToken externalToken){    using var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(5));    using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(externalToken, timeoutCts.Token);

try { await LongRunningOperationAsync(linkedCts.Token); } catch (OperationCanceledException) { Console.WriteLine("操作已取消或超时。"); }}


2. SynchronizationContext 与任务调度器



理解 SynchronizationContext 对于处理 UI 线程(WPF、WinForms)和 ASP.NET Core 至关重要。在进阶层面,您可以创建自己的同步上下文。



为线程池配置上下文

默认情况下,await 会捕获当前的 SynchronizationContext。为避免此行为(并防止死锁),请使用 ConfigureAwait(false)。



public async Task ProcessDataAsync(){    // 此代码在原始上下文中执行(例如 UI)    await Task.Run(() => HeavyComputation()).ConfigureAwait(false);

// 使用 ConfigureAwait(false) 后 —— 在线程池上下文中 // 无法访问 UI 元素! Console.WriteLine("在线程池中执行");}


创建自定义调度器

您可以实现自己的 TaskScheduler,例如,用于限制同时执行的任务数量(类似于调度器级别的 SemaphoreSlim)。



public class LimitedConcurrencyTaskScheduler : TaskScheduler{    private readonly SemaphoreSlim _semaphore;    private int _runningTasks;

public LimitedConcurrencyTaskScheduler(int maxConcurrency) { _semaphore = new SemaphoreSlim(maxConcurrency);

博客

书籍推荐