2018年11月21日水曜日

C#のListでGetRange()とToCopy()とBlockCopy()を比較してみた

知ってる人にとってはばかばかしいと思いますが、C#素人の悲しさ故に何でもやってみないとわからないので、恥ずかしながら今回は単純なリストの範囲コピーの速度比較をやってみました。

測定条件:
コピー元: List<float> 100000件
コピー先: float[]
コピー条件: コピー元の4000件目から最後まで(96000件)
コピー回数: 100000回

結果:

メソッドコピー先を毎回確保コピー先を使いまわし
GetRange23327ms(使いまわせない)
ToCopy11499ms1958ms
BlockCopy20000ms11862ms

コピー先を使いまわす版は異常に高いnewのコストを除外するために測定しました。
とりあえずToCopyがいいみたいです。
以上です。

おまけ:
こんなコードで測定しました。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public class ListCopySpeedTest 
  { 
    List<float> fl = new List<float>(); 
    const int membernum = 100000; 
    const int testcount = 100000; 
    const int startindex = 4000; 
    void init() 
    { 
      Random r = new Random(); 
      for ( int i = 0; i < membernum; i++ ) { 
        fl.Add( (float)r.NextDouble() ); 
      } 
    } 
    float[] GetRange( float[] fa ) 
    { 
      fa = fl.GetRange( startindex, membernum - startindex ).ToArray(); 
      return fa; 
    } 
    float[] ToCopy( float[] fa ) 
    { 
      if ( fa == null ) { 
        fa = new float[ membernum - startindex ]; 
      } 
      fl.CopyTo( startindex, fa, 0, membernum - startindex ); 
      return fa; 
    } 
    float[] BlockCopy( float[] fa ) 
    { 
      if ( fa == null ) { 
        fa = new float[ membernum - startindex ]; 
      } 
      Buffer.BlockCopy( fl.ToArray(), startindex, fa, 0, membernum - startindex ); 
      return fa; 
    } 
    delegate float[] testfunc_t(float[] floatarray); 
    void testfunc( Stopwatch sw, testfunc_t f ) 
    { 
      float[] fa = null; 
      for ( int j = 0; j < 2; j++ ) { 
        sw.Reset(); 
        sw.Start(); 
        for ( int i = 0; i < testcount; i++ ) { 
          f( fa ); 
        } 
        sw.Stop(); 
        Console.WriteLine( f.Method.Name + ": " + sw.ElapsedMilliseconds + "ms" ); 
        fa = new float[ membernum - startindex ]; 
      } 
    } 
    public void test() 
    { 
      init(); 
      Stopwatch sw = new Stopwatch(); 
      testfunc( sw, GetRange ); 
      testfunc( sw, ToCopy ); 
      testfunc( sw, BlockCopy ); 
    } 
  } 
  class Program 
  { 
    static void Main( string[] args ) 
    { 
      new ListCopySpeedTest().test(); 
      Console.Read(); 
    } 
  } 

0 件のコメント:

コメントを投稿