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

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

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

开始课程

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

\n\n

在现代 C# (.NET) 开发中,高效管理并发与多线程的能力是区分资深工程师与新手的标志。仅凭 Thread 和简单锁的基础知识,已不足以构建高性能、响应迅速且可扩展的应用程序。本文将深入探讨进阶技术:从深刻理解 async/await 到使用 System.Threading.Channels 和 TPL Dataflow。本文面向已掌握多线程基础的开发者。

\n\n

1. 深入理解 async/await 与 SynchronizationContext

\n\n

许多开发者使用 async/await,但并未完全理解任务调度器 (Task Scheduler) 和 SynchronizationContext 如何管理延续 (continuations)。在进阶层面,控制 await 之后代码在哪个线程执行至关重要。

\n\n

默认情况下,await 会捕获当前的 SynchronizationContext(或 TaskScheduler)。在 UI 应用程序(WPF、WinForms)中,这会将执行返回到主线程。在 ASP.NET Core 和控制台应用程序中,上下文通常不存在,延续可能会在线程池中的任意线程上执行。

\n\n

如需精细控制,请使用 ConfigureAwait(false)。这会告知运行时不要尝试返回到原始上下文,从而提高性能并防止库代码中的死锁。

\n\n
public async Task<string> FetchDataAsync(HttpClient client)\n{\n    // 延续不会捕获上下文\n    var result = await client.GetStringAsync("https://api.example.com")\n                              .ConfigureAwait(false);\n    // 此代码将在线程池中的任意线程上执行\n    return ProcessResult(result);\n}\n\npublic async Task<string> FetchDataWithContextAsync(HttpClient client)\n{\n    // 延续将返回到原始上下文(例如 UI 线程)\n    var result = await client.GetStringAsync("https://api.example.com");\n    // 此代码保证在原始上下文中执行\n    return ProcessResult(result);\n}
\n\n

进阶建议: 为非常规场景创建自定义 SynchronizationContext,例如组织具有固定线程数的任务队列。

\n\n

2. 任务并行库 (TPL) 与数据并行

\n\n

TPL 为并行提供了高级抽象。Parallel.For 和 Parallel.ForEach 会自动将集合拆分为块 (chunks) 并分配到线程上。然而,在进阶层面,需要理解如何配置并行度以及异常处理。

\n\n

使用 ParallelOptions 限制线程数,并使用 ParallelLoopState 提前退出循环。

\n\n
var options = new ParallelOptions\n{\n    MaxDegreeOfParallelism = Environment.ProcessorCount / 2 // 使用一半的核心\n};\n\nParallel.ForEach(sourceData, options, (item, state) =>\n{\n    try\n    {\n        // 耗时操作\n        ProcessItem(item);\n    }\n    catch (Exception ex)\n    {\n        // 记录日志并中断执行\n        Console.WriteLine($"错误: {ex.Message}");\n        state.Stop(); // 中断循环执行\n    }\n});
\n\n

重要提示: Parallel.ForEach 不保证处理顺序。如果顺序很重要,请使用带索引的 Parallel.ForEach 或 PLINQ (AsParallel().AsOrdered())。

\n\n

3. 通道 (System.Threading.Channels) 用于生产者-消费者模式

\n\n

Channel<T> 类自 .NET Core 3.0 引入,已成为生产者-消费者场景的强大工具。它是线程安全、异步且高效的。通道分为

博客

书籍推荐