Movatterモバイル変換


[0]ホーム

URL:


Logo

目次

概要

Ver. 4.0

マルチコア CPU の普及に伴って、並列処理の重要性が増しています。この時代背景に合わせるかのように、.NET Framework 4で並列処理用のライブラリが追加されました。

Parallel クラス

まずは、制御フロー(「制御フロー」参照)の並列化です。Parallel クラス(System.Threading.Tasks 名前空間)を使うことで、通常の for 文や foreach 文に非常に似た書き方で並列処理を行えます。

Parallel クラスは Invoke、For、ForEach の3つの静的メソッドを持っています。

Parallel クラスを使った制御フローの並列化
メソッド逐次処理版並列処理版
Invoke
A();B();C();
Parallel.Invoke(A, B, C);
For
for (int i = 0; i < N; i++){Console.WriteLine(i * i);}
Parallel.For(0, N, i =>{Console.WriteLine(i * i);});
ForEach
var data =Enumerable.Range(0, N);foreach (var xin data){Console.WriteLine(x * x);}
var data =Enumerable.Range(0, N);Parallel.ForEach(data, x =>{Console.WriteLine(x * x);});

逐次処理とほとんど同じ書き方で並列処理ができます。

ただし、複数のスレッドから同じデータを読み書きする場合には「排他制御」が必要なので注意してください。例えば、以下のような処理は、単に foreach 文を Parallel.ForEach メソッドに置き換えるだけでなく、ロックが必要です。

var data =Enumerable.Range(0, N);var sum = 0;foreach (var xin data){    sum += x;}Console.WriteLine(sum);

以下のように、sum += x の部分にロックを掛けます。

var data =Enumerable.Range(0, N);var sum = 0;Parallel.ForEach(data, x =>{lock (data) sum += x;});Console.WriteLine(sum);

ロック自体がそれなりにオーバーヘッドのかかる処理なので、この例の場合、並列化するとかえって遅くなる可能性があります。

Parallel LINQ

LINQ」 に対する並列化の仕組みも用意されています。System.Linq 名前空間に ParallelEnumerable というクラスが追加されていて、このクラスで定義されている AsParallel 拡張メソッドを使えば、LINQ クエリを並列化できます。(データ ソースに対して .AsParallel() を付けるだけです。)

var data =Enumerable.Range(0, N);var sqSum = data.AsParallel().Sum(x => x * x);Console.WriteLine(sqSum);

必要な「排他制御」は適宜ライブラリ内で行ってくれるので、こちらはロックが不要です。なので、データ ストリーム(「ストリームとパイプライン」参照)に対する並列処理は、Parallel クラスを使うよりも、こちらを使う方がおすすめです。

ただし、多少の工夫が必要な場合もあります。例えば、1つ前の要素を参照したいというような場合、以下のように書いてしまいがちです。

// 1つ前の値を保存しておくvar prev = data.First();var max =int.MinValue;foreach (var xin data.Skip(1)){// 階差の最大値    max =Math.Max(x - prev, max);    prev = x;}

並列化したい場合、必ずしも順序の保証がないので、prev = x; では「1つ前の要素を保存」という処理になりません。以下のような工夫が必要になります。

// 1項ずらしたデータ ストリームと Zipvar difference = data.Zip(data.Skip(1), (i, j) => j - i);// そのあと、AsParallelvar max = difference.AsParallel().Max();

更新履歴

更新:言語バージョンの指定

[C#]

ファイル ベース実行

[C#]

C# 14.0 の新機能

[C#]

更新:[雑記] オーバーロード解決

[C#]

型の分割定義 (partial)

[C#]

ブログ

C# 14 の破壊的変更点(First-class Span)

ファイナライザー

文字列リテラルを data セクションに UTF-8 で書き込む案

nameof(T<>)

First-class な Span 型


誤字等を見つけた場合や、ご意見・ご要望がございましたら、GitHub の Issues まで気兼ねなくご連絡ください。

[8]ページ先頭

©2009-2025 Movatter.jp