Parallel.Foreach的基础知识

Parallel.Foreach是C#中用于并行迭代数组或集合的一种方式。它允许我们在不显式编写多线程代码的情况下,将迭代工作并行化。在这篇文章中,我们将探讨Parallel.Foreach的基础知识、使用方法和一些案例说明。

## 基础知识

在介绍Parallel.Foreach之前,先来了解一下多线程的一些基本概念。线程是操作系统可以进行调度的最小单位。一个进程可以包含多个线程,这些线程可以并发地执行不同的任务。在多线程编程中,共享内存的读写操作涉及到线程同步的问题,如果不加锁,会导致数据不一致。因此,多线程编程需要对锁的使用有严格要求。

Parallel.Foreach实现了线程池的方式来执行并行迭代。线程池是一种多线程技术,它预先启动一定数量的线程,这些线程在任务执行完成后不会立即终止,而是继续保持等待状态,以便下一次任务的到来。这种做法可以避免反复创建和销毁线程的开销。

## 使用方法

Parallel.Foreach的语法如下:

```csharp

Parallel.ForEach(IEnumerable source, Action body);

```

其中,source是要迭代的数据集合,body是要执行的具体操作。接下来,我们将通过一个示例来说明如何使用Parallel.Foreach。

```csharp

using System;

using System.Threading.Tasks;

namespace ParallelForEachDemo

{

class Program

{

static void Main(string[] args)

{

int[] array = new int[10000];

for (int i = 0; i < array.Length; i++)

{

array[i] = i + 1;

}

Parallel.ForEach(array, item =>

{

Console.WriteLine($"Thread {Task.CurrentId} processing item {item}");

});

Console.ReadLine();

}

}

}

```

上面的代码中,我们创建了一个长度为10000的整型数组,然后使用Parallel.Foreach并行遍历这个数组,并输出当前线程ID和遍历的元素值。可以看到,输出结果并不是按照数组中元素的顺序输出的,这是因为Parallel.Foreach默认会按照任务的完成情况来调度多个线程的执行顺序。

Parallel.Foreach也允许我们在迭代过程中传递一个状态对象,如下所示:

```csharp

using System;

using System.Threading.Tasks;

namespace ParallelForEachDemo

{

class Program

{

static void Main(string[] args)

{

int[] array = new int[10000];

int sum = 0;

for (int i = 0; i < array.Length; i++)

{

array[i] = i + 1;

}

Parallel.ForEach(array, () => 0, (item, loopState, localSum) =>

{

localSum += item;

Console.WriteLine($"Thread {Task.CurrentId} processing item {item}");

return localSum;

},

(localSum) => Interlocked.Add(ref sum, localSum));

Console.WriteLine($"The sum is {sum}");

Console.ReadLine();

}

}

}

```

上述示例代码中,我们在迭代过程中使用一个本地变量localSum保存每个线程处理的累加值,每个线程执行完后,都会将自己的localSum值加到全局变量sum中。这种方式是安全的,因为Interlocked.Add方法会保证原子操作。在Parallel.Foreach中,loopState参数用于中止并行迭代,可以用来控制任务的执行。

## 案例说明

下面,我们将给出一些案例,以便更好的理解Parallel.Foreach的使用场景。

### 1. 遍历文件夹中的所有文件

在有大量文件需要处理时,如果使用单线程处理,可能会增加 CPU 负载,延长处理时间,降低计算机性能。下面的示例代码演示了如何使用Parallel.Foreach并行遍历指定文件夹中的所有文件。

```csharp

using System;

using System.IO;

using System.Threading.Tasks;

namespace ParallelForEachDemo

{

class Program

{

static void Main(string[] args)

{

string folderPath = @"D:\Documents";

Parallel.ForEach(Directory.GetFiles(folderPath), filePath =>

{

Console.WriteLine($"Thread {Task.CurrentId} processing file {filePath}");

// Do something with the file

});

Console.ReadLine();

}

}

}

```

上述代码中,我们使用Directory.GetFiles方法获取指定文件夹中的所有文件路径,然后使用Parallel.Foreach并行遍历这些文件,并输出当前线程ID和处理的文件路径。

### 2. 多维数组操作

多维数组在数据处理领域中非常重要。在使用Parallel.Foreach遍历多维数组时,我们通常需要使用多个for循环来迭代每个维度,如下所示:

```csharp

using System;

using System.Threading.Tasks;

namespace ParallelForEachDemo

{

class Program

{

static void Main(string[] args)

{

int[,] matrix = new int[1000, 1000];

long sum = 0;

for (int i = 0; i < matrix.GetLength(0); i++)

{

for (int j = 0; j < matrix.GetLength(1); j++)

{

matrix[i, j] = i * j;

}

}

Parallel.For(0, matrix.GetLength(0), i =>

{

for (int j = 0; j < matrix.GetLength(1); j++)

{

Interlocked.Add(ref sum, matrix[i, j]);

}

Console.WriteLine($"Thread {Task.CurrentId} processing row {i}");

});

Console.WriteLine($"The sum is {sum}");

Console.ReadLine();

}

}

}

```

在上述示例代码中,我们构造了一个1000*1000的二维数组,然后使用Parallel.For并行遍历数组的第一维,每个线程负责处理一行数据。由于多线程访问共享内存时可能涉及到数据不一致的问题,我们使用了Interlocked.Add方法来对sum进行原子操作。

## 总结

Parallel.Foreach是一种方便实用的并行遍历数据的方式,它可以帮助我们快速地实现多线程程序,提升程序运行效率。在使用Parallel.Foreach时,我们需要注意线程同步和线程安全问题,合理地控制并行度以避免 CPU 过载。 如果你喜欢我们三七知识分享网站的文章, 欢迎您分享或收藏知识分享网站文章 欢迎您到我们的网站逛逛喔!https://www.ynyuzhu.com/

点赞(71) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿
发表
评论
返回
顶部