• C#中几种遍历列表的方法性能比较
  • 发布于 1天前
  • 19 热度
    0 评论
遍历集合是 C# 程序员天天要干的事。数据多了、逻辑复杂了,性能、异步、并发就统统成了问题。C# 提供了几种不同的遍历方式,各有优缺点,今天我们来用真实代码和具体场景,一次讲清楚:
.Parallel.ForEach 和 Parallel.ForEachAsync
.List<T>.ForEach
.foreach(包括配合异步方法)
1. Parallel.ForEach:多线程并发执行,性能猛兽
当你有大量数据需要同时处理,而且每个处理之间没有依赖关系,用 Parallel.ForEach 能显著提升性能。
Parallel.ForEach(myList, item =>
{
    ProcessHeavy(item); // 耗时的同步任务
});
这个方法会自动帮你分配线程池中的线程去并发执行任务。唯一要注意的是,它不保证顺序,多个任务是同时跑的。如果你访问了共享资源(比如同一个文件、变量),就要手动加锁或用线程安全的方式处理。

.NET 6 起还支持异步版本:
await Parallel.ForEachAsync(myList, async (item, token) =>
{
    await ProcessAsync(item); // 异步耗时任务,如 HTTP 请求
});
这个非常适合需要同时跑多个异步请求,比如发起 100 个 API 调用、同时上传一堆文件等。
适合场景:
.并发执行没有顺序依赖的任务
.大批量数据处理

.高性能需求场景,如后台服务、图像处理等


2. List<T>.ForEach:优雅简洁,但局限也多
很多人说的 “Enumerable.ForEach” 其实并不存在,真正的是 List<T>.ForEach 方法。它是 List 自带的实例方法,不是 LINQ 扩展。
var list = new List<int> { 1, 2, 3 };
list.ForEach(item => Console.WriteLine(item));
看起来非常简洁,适合快速写小脚本或者 UI 层的简单逻辑处理。但它只支持 List 类型,而且不能用于异步操作。你要是这样写:
list.ForEach(async item => await DoSomethingAsync(item)); // 错误写法!
这段代码会变成 async void,出了错都捕不到,调试困难,不建议这样使用。

适合场景:
.小数据量操作
.不涉及异步或并发的逻辑

.代码洁癖患者追求简短写法


3. foreach + async:稳妥靠谱,顺序清晰
最经典的写法仍然是 foreach,它的好处是稳。你可以明确知道顺序、执行时机、异常处理,配合异步也很好用。
foreach (var item in myList)
{
    await DoSomethingAsync(item); // 一个个执行
}
虽然不能并发,但非常适合对顺序敏感的场景,比如依次写数据库、依次上传文件、依次记录日志等。
.NET 还支持 await foreach 遍历异步流,比如从数据库流式读取数据:
// 堆代码 duidaima.com
await foreach (var row in GetDataAsync())
{
    Console.WriteLine(row);
}
这类写法适合消息队列、数据库分页加载、SignalR 等场景。
适合场景:
.需要确保执行顺序
.异步操作逐个进行,稳定性优先

.可配合异步流读取大数据量


4. 对比总结表
遍历方式 是否支持并发 是否支持异步 顺序是否保证 支持的集合类型 推荐使用场景
Parallel.ForEach 所有 IEnumerable 并行处理 CPU 密集型任务
Parallel.ForEachAsync 所有 IEnumerable 并发处理异步任务(如接口、I/O)
List<T>.ForEach ❌(⚠不支持) 仅限 List<T> 小量数据处理,语法简洁
foreach + await 所有 IEnumerable 顺序异步执行,控制清晰
await foreach(异步流) 异步可枚举对象 异步流处理,如数据库流、消息流等

结语

1.如果你任务之间没啥依赖,又想快, 并发用 Parallel.ForEach 或 Parallel.ForEachAsync 。
2.如果只是小脚本、小功能,List<T>.ForEach 最舒服,但别写异步逻辑进去。
3.如果你想代码靠谱、不出事,特别是对顺序敏感的异步操作,还是老老实实用 foreach + await。

用户评论