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 件のコメント:

コメントを投稿