More Related Content
Similar to Linqの速度測ってみた (20)
More from Core Concept Technologies (20)
Linqの速度測ってみた
- 2. © 2019 Core Concept Technologies Inc.
安宅彰一朗(アタケショウイチロウ)
所属:本社事業部
役職:シニアエンジニア
好きな食べ物:ハンバーガー
最近はSpringBootでJavaJavaしてます
自己紹介
1CONFIDENTIAL
- 3. © 2019 Core Concept Technologies Inc.
ざっくり言うと集合をSQLっぽく扱える仕組みです。こんなの。
LINQとは
2CONFIDENTIAL
var ret = collection
.Where(x => x >= 500) // 条件で絞って
.Select(x => x * x) // 個別に処理して
.OrderBy(x => x); // ソートする
C#的にはIEnumerableインターフェイスを実装しているオブジェクトに
対してGenerics、拡張メソッドで実現されているライブラリです。
※ちなみにこの資料はなにか素晴らしい知見が得られるようなものではなく
思うがままLINQの速度を測ってみた、ただそれだけです!
- 4. © 2019 Core Concept Technologies Inc.
以下のようなインターフェイスです。
LINQはこれに対して処理処理を行うものです。
なのでLINQに対応した独自クラスなんかも簡単に作れちゃいます。
※今回は実装まではやりません。気になる人は実装してみてください。
IEnumerable(アイエニュメラブル)ってなんぞ?
3CONFIDENTIAL
class DemoList : IEnumerable
{
public IEnumerator GetEnumerator() { return new DemoListEnumerator(); }
class DemoListEnumerator : IEnumerator
{
public Object Current { get; } // 今いる場所
public bool MoveNext() { return true; } // 次へ移動(移動できればtrue)
public void Reset() { } // 今いる場所を最初に戻す
}
}
- 5. © 2019 Core Concept Technologies Inc.
ICollectionならプロパティあるんだから使えばいいじゃん的な
最適化が入ってますが、主要実装はこれだけ。とってもシンプル!
https://github.com/dotnet/corefx/blob/master/src/System.Linq/src/System/Linq/Count.cs
ちょっとCount覗いてみましょう
4CONFIDENTIAL
public static int Count<TSource>(this IEnumerable<TSource> source)
{
:
int count = 0;
using (IEnumerator<TSource> e = source.GetEnumerator())
{
checked
{
while (e.MoveNext())
{
count++;
}
}
}
return count;
}
- 6. © 2019 Core Concept Technologies Inc.
準備
5CONFIDENTIAL
// 1~10000000ランダム数列1億件
List<int> listRandom = SpeedTestBase.CreateList(100000000);
// 1~1億の数列
IEnumerable<int> enumerableNum = Enumerable.Range(1, 100000000);
端末スペック
CPU:Core i5(4コア)
メモリ:16GB
- 7. © 2019 Core Concept Technologies Inc.
Count-List : 00:00:00.0005399
Count-IEnumerable : 00:00:00.2788430
ListとIEnumerableのCountは全然違う
6CONFIDENTIAL
sw.Restart();
var result_01_1 = listRandom.Count();
sw.Stop();
Console.WriteLine("Count-List : " + sw.Elapsed);
sw.Restart();
var result_01_2 = enumerableNum.Count();
sw.Stop();
Console.WriteLine("Count-IEnumerable : " + sw.Elapsed);
- 8. © 2019 Core Concept Technologies Inc.
Max-LINQ : 00:00:00.6924498
Max-foreach : 00:00:00.4709000
Max(最大値)
7CONFIDENTIAL
sw.Restart();
var result_02_1 = listRandom.Max();
sw.Stop();
Console.WriteLine("Max-LINQ : " + sw.Elapsed);
sw.Restart();
int max = 0;
foreach (int i in listRandom)
{
if(max < i) { max = i; }
}
sw.Stop();
Console.WriteLine("Max-foreach : " + sw.Elapsed);
- 9. © 2019 Core Concept Technologies Inc.
Where-LINQ-toList : 00:00:00.8328413
Where-LINQ-foreach : 00:00:00.7824337
Where-foreach : 00:00:00.6183393
Where(抽出)
8CONFIDENTIAL
sw.Restart();
var result_03_1 = listRandom.Where(x => x % 123 == 0).ToList();
sw.Stop();
Console.WriteLine("Where-LINQ-toList : " + sw.Elapsed);
sw.Restart();
var result_03_2 = listRandom.Where(x => x % 123 == 0);
foreach (var x in result_03_2) { }
sw.Stop();
Console.WriteLine("Where-LINQ-foreach : " + sw.Elapsed);
sw.Restart();
var result_03_3 = new List<int>();
foreach (var x in listRandom)
{
if (x % 123 == 0)
{
result_03_3.Add(x * x);
}
}
sw.Stop();
Console.WriteLine("Where-foreach : " + sw.Elapsed);
- 10. © 2019 Core Concept Technologies Inc.
Parallel LINQ (PLINQ) は、LINQ パターンの並列実装です。 PLINQ クエリは、あらゆ
る意味において、並列ではない LINQ to Objects クエリに似ています。 PLINQ クエリ
は、LINQ の順次クエリと同様、メモリ内の IEnumerable また
は IEnumerable<T> データ ソースで実行され、遅延実行が存在するので、クエリが列
挙されるまでは実行されません。 主な相違点は、PLINQ は、システムのすべてのプロ
セッサを十分に活用しようとする点です。 そのために、データ ソースをセグメントに
パーティション分割し、複数のプロセッサで個々のワーカー スレッドの各セグメントに
対してクエリを並行実行します。 多くの場合、並行実行によって、クエリは非常に高速
に処理されます。
https://docs.microsoft.com/ja-jp/dotnet/standard/parallel-programming/parallel-
linq-plinq
そういえばPLINQってあったやん
9CONFIDENTIAL
- 11. © 2019 Core Concept Technologies Inc.
Parallel LINQ (PLINQ) は、LINQ パターンの並列実装です。 PLINQ クエリは、あらゆ
る意味において、並列ではない LINQ to Objects クエリに似ています。 PLINQ クエリ
は、LINQ の順次クエリと同様、メモリ内の IEnumerable また
は IEnumerable<T> データ ソースで実行され、遅延実行が存在するので、クエリが列
挙されるまでは実行されません。 主な相違点は、PLINQ は、システムのすべてのプロ
セッサを十分に活用しようとする点です。 そのために、データ ソースをセグメントに
パーティション分割し、複数のプロセッサで個々のワーカー スレッドの各セグメントに
対してクエリを並行実行します。 多くの場合、並行実行によって、クエリは非常に高速
に処理されます。
https://docs.microsoft.com/ja-jp/dotnet/standard/parallel-programming/parallel-
linq-plinq
そういえばPLINQってあったやん
10CONFIDENTIAL
まあ理屈はどうでもいいんですよ
測ってみましょう!
- 12. © 2019 Core Concept Technologies Inc.
PLINQ-Heavy-ForAll : 00:00:07.5491188
PLINQ-Heavy-foreach : 00:00:26.5182497
PLINQのForAllとforeach(重い処理)
11CONFIDENTIAL
sw.Restart();
var result_03_4 = listRandom.AsParallel().Where(x => x % 123 == 0);
result_03_4.ForAll(x => SpeedTestBase.HeavyProc(x));
sw.Stop();
Console.WriteLine("PLINQ-Heavy-ForAll : " + sw.Elapsed);
sw.Restart();
var result_03_5 = listRandom.AsParallel().Where(x => x % 123 == 0);
foreach(var x in result_03_5)
{
SpeedTestBase.HeavyProc(x);
}
sw.Stop();
Console.WriteLine("PLINQ-Heavy-foreach : " + sw.Elapsed);
因数分解してます
- 13. © 2019 Core Concept Technologies Inc.
Microsoftドキュメントちゃんとしてるから大好きです。
https://docs.microsoft.com/ja-jp/dotnet/standard/parallel-
programming/introduction-to-plinq
なんでなんでしたっけ?
12CONFIDENTIAL
- 14. © 2019 Core Concept Technologies Inc.
PLINQ-light-ForAll : 00:00:00.4169516
PLINQ-light-foreach : 00:00:00.3145349
PLINQのForAllとforeach(軽い処理)
13CONFIDENTIAL
sw.Restart();
var result_04_1 = listRandom.AsParallel().Where(x => x % 123 == 0);
result_04_1.ForAll(x => SpeedTestBase.lightProc(x));
sw.Stop();
Console.WriteLine("PLINQ-light-ForAll : " + sw.Elapsed);
sw.Restart();
var result_04_2 = listRandom.AsParallel().Where(x => x % 123 == 0);
foreach (var x in result_04_2)
{
SpeedTestBase.lightProc(x);
}
sw.Stop();
Console.WriteLine("PLINQ-light-foreach : " + sw.Elapsed);
1足してます
- 15. © 2019 Core Concept Technologies Inc.
学び
14CONFIDENTIAL
- 16. © 2019 Core Concept Technologies Inc.
1.PowerPointにソースコード貼るのめちゃ大変
学び
15CONFIDENTIAL
- 17. © 2019 Core Concept Technologies Inc.
1.PowerPointにソースコード貼るのめちゃ大変
2.確かにLINQはちょっと遅い、遅いけど、、、
* 読みやすい(生産性向上)
* 遅延評価(省メモリ、無限ループもいけちゃう)
* だいたい1億件ループとか業務でしないし
* 並列処理はLINQ関係なく難しい
学び
16CONFIDENTIAL
- 18. © 2019 Core Concept Technologies Inc.
1.PowerPointにソースコード貼るのめちゃ大変
2.確かにLINQはちょっと遅い、遅いけど、、、
* 読みやすい(生産性向上)
* 遅延評価(省メモリ、無限ループもいけちゃう)
* だいたい1億件ループとか業務でしないし
* 並列処理はLINQ関係なく難しい
3.でも確かに良くない書き方はあって。。。
学び
17CONFIDENTIAL
- 19. © 2019 Core Concept Technologies Inc.
やりがち1
18CONFIDENTIAL
sw.Restart();
var result_11_1 = listRandom.Where(x => x % 123 == 0).Select(x => x * x);
if(result_11_1.Count() > 0) { }
sw.Stop();
Console.WriteLine("time-11-1 : " + sw.Elapsed);
sw.Restart();
var result_11_2 = listRandom.Where(x => x % 123 == 0).Select(x => x * x);
if (result_11_2.Any()) { }
sw.Stop();
Console.WriteLine("time-11-2 : " + sw.Elapsed);
存在チェックしたいだけなのにCountしちゃう
time-11-1 : 00:00:00.6972058
time-11-2 : 00:00:00.0001552
- 20. © 2019 Core Concept Technologies Inc.
やりがち2
19CONFIDENTIAL
全部処理する必要ないのにListで受けちゃう
sw.Restart();
var result_12_1 = listRandom.Where(x => x % 123 == 0).ToList();
double sum1 = 0;
foreach (var i in result_12_1)
{
// 合計が1億超えたら終了みたいな
sum1 += i;
if (sum1 > 10000000) { break; }
}
sw.Stop();
Console.WriteLine("time-12-1 : " + sw.Elapsed);
sw.Restart();
var result_12_2 = listRandom.Where(x => x % 123 == 0);
double sum2 = 0;
foreach (var i in result_12_2)
{
// 合計が1億超えたら終了みたいな
sum2 += i;
if (sum2 > 10000000) { break; }
}
sw.Stop();
Console.WriteLine("time-12-2 : " + sw.Elapsed);
time-12-1 : 00:00:00.6682446
time-12-2 : 00:00:00.0001236
- 21. © 2019 Core Concept Technologies Inc.
やりがち3
20CONFIDENTIAL
途中まで同じなのに遅延評価しちゃう
sw.Restart();
var result_13_11 = listRandom.Where(x => x % 123 == 0).Where(x => x > 0).Count();
var result_13_12 = listRandom.Where(x => x % 123 == 0).Where(x => x > 0).Max();
var result_13_13 = listRandom.Where(x => x % 123 == 0).Where(x => x > 0).Min();
sw.Stop();
Console.WriteLine("time-13-1 : " + sw.Elapsed);
sw.Restart();
var temp = listRandom.Where(x => x % 123 == 0).Where(x => x > 0).ToList();
var result_13_21 = temp.Count();
var result_13_22 = temp.Max();
var result_13_23 = temp.Min();
sw.Stop();
Console.WriteLine("time-13-2 : " + sw.Elapsed);
time-13-1 : 00:00:02.4088091
time-13-2 : 00:00:00.8282709