知识问答

C#并发实战记录之Parallel.ForEach使用

C#并发实战记录之Parallel.ForEach使用

什么是 Parallel.ForEach?

Parallel.ForEach 是一个并行迭代器,它允许并行执行循环。简单的说,就是可以将一个大型的循环任务拆分成多个子任务,使得多个任务可以并行执行,提高执行效率。

如何使用 Parallel.ForEach?

Parallel.ForEach 的用法非常简单,只需要提供一个集合和一个委托即可。

Parallel.ForEach(source, item => {    // 任务代码});

其中,source 参数是要遍历的集合,item 参数表示集合中的每个元素,委托中的代码就是每个元素需要执行的任务。

Parallel.ForEach 的重载方法

Parallel.ForEach 还有其他的重载方法,可以设置并行度、取消任务等等。具体的重载方法请参考MSDN文档。

Parallel.ForEach 示例

下面是两个简单的 Parallel.ForEach 示例:

示例1:统计一个目录下的文件大小

var fileSize = new long[1];Parallel.ForEach(Directory.GetFiles(@"C:\Test"), file => {    var fileInfo = new FileInfo(file);    Interlocked.Add(ref fileSize[0], fileInfo.Length);});Console.WriteLine($"Total file size: {fileSize[0]} bytes");

上述代码中,我们使用 Parallel.ForEach 遍历指定目录下的所有文件,并求出文件总大小。使用 Interlocked.Add 方法将每个任务中得到的文件大小相加,最终输出总大小。

示例2:并行下载网页内容

var urls = new[] {"http://www.example.com", "http://www.baidu.com", "http://www.Google.com"};Parallel.ForEach(urls, url => {    using(var client = new HttpClient()) {        var content = client.GetStringAsync(url).Result;        Console.WriteLine($"{url} content length: {content.Length}");    }});

上述代码中,我们使用 Parallel.ForEach 并行下载三个网站的内容,并输出网页内容的长度。

需要注意的是,HttpClient 中的 GetStringAsync 是异步方法,但是我们在代码中使用了它的阻塞版本 Result。这是因为 Parallel.ForEach 不支持异步方法,所以我们必须使用它的同步方法。如果需要使用异步方法并发下载,可以使用其他的并发库,比如 TPL Dataflow。

总结

Parallel.ForEach 是一个非常有用的并发工具,可以将大型的循环任务拆分成多个子任务,提高程序的执行效率。但是在使用的过程中需要注意线程安全问题,以及对异步方法的支持。