2

C# 3.5 と VS 2010 Ultimate を使用しています。

ネストされた 4 つの for ループを持つ機械学習アルゴリズムを (速度のために) 最適化しています。同じオブジェクトの再割り当てが多数あるため、単純なキャッシュ (オブジェクトのテンソル) によってパフォーマンスが大幅に向上する可能性があることがわかりました。

導入前と導入後はこちら。

前:

four nested for-loops:
   var object = new object(3 parameters);
   Calculate(object, other params)

後:

var cache = new object[count1,count2,count3];
three nested for-loops:
   cache[param1, param2, param3] = new object(3 params);

four nested for-loops:
   var object = cache[3 parameters];
   Calculate(object, other params)

私は両方の方法をプロファイリングしましたが、「前」のバージョンは GC に約 18% の時間が費やされてかなり高速でしたが、「後」のバージョンは GC に約 88% の時間が費やされました。このキャッシュの追加によって GC アクティビティが増加したことは明らかですが、これがどのように可能であるかはわかりません。

アプリケーションで多くの寿命の長いオブジェクトを使用しています。プロファイリングの時点で、私のマシンには大きな負荷がかかっていませんでした。テンソルは、多次元配列 (ギザギザ配列ではない) を使用して実装されました。上記の両方の方法の最も内側のループは、Parallel.For構造体を使用して実装されています。ここでは、ループの直前に小さなdouble配列を割り当てています。

GC に費やす時間を短縮するにはどうすればよいですか?

編集 #1: 結果は確かにリリース モードからのものです。

編集 #2: after メソッドの 4 つの for ループの実際のコード:

List<int> labels = // count = 80
List<int> tokens = // count = 35

var table = new double[tokens.Count, labels.Count, labels.Count];
var cachedObjects = new CachedObject[tokens.Count, labels.Count, labels.Count];
for (int k = 0; k < tokens.Count; k++)
{
    foreach (var tagCurrent in labels) 
    {
        foreach (var labelBack in labels)
        {
            double[] value = new double[labels.Count];
            Parallel.For(0, labels.Count, (i) => 
            {
                CachedObject CachedObject = cachedObjects[k, labelsBackFurther[i], labelBack];

                var me = ModelEstimate(vOptimal, CachedObject, tagCurrent, labels);
                value[i] = table[k - 1, labels[i], labelBack] * me;
            }); 

            var maxValue = 0;
            var maxTagIdx = 0;
            for (int j = 0; j < value.Length; j++)
            {
                var item = value[j];
                if (item > maxValue)
                {
                    maxValue = item;
                    maxTagIdx = j;
                }
            }

            table[k, labelBack, tagCurrent] = maxValue;
        }
    }
}
4

4 に答える 4

2

GC は、割り当て数と生存者数の 2 つの要因の影響を受けます。

割り当ては収集をトリガーするため、割り当てる量が多いほど収集の頻度が高くなります。

アプリが大量のデータを保持している場合、Gen 2 コレクションは非常に高価になる可能性があります。GC に多くの時間が費やされている場合は、通常、これが当てはまります (サイズが制限されているため、Gen 0 と 1 の収集は高速です)。

あなたの場合、キャッシュを保持したいようです。これを行う場合は、高価な Gen 2 収集をトリガーしたくないため、割り当てを抑える必要があります。

PerfViewを使用して割り当てを追跡できます。

于 2013-06-18T16:16:30.003 に答える
0

GC に費やす時間を短縮するにはどうすればよいですか?

Microsoftの「ガベージ コレクション ガイドライン」には、非常に興味深い提案があり、次のように述べられています。

キャッシュされたデータを操作する場合は弱参照の使用を検討してください。これにより、必要に応じてキャッシュされたオブジェクトを簡単に復元したり、メモリ不足のときにガベージ コレクションによって解放したりできます。

void SomeMethod() 
{
  // Create a collection
  var arr = new ArrayList(5);
  // Create a custom object
  var mo = new MyObject();
  // Create a WeakReference object from the custom object
  var wk = new WeakReference(mo);
  // Add the WeakReference object to the collection
  arr.Add(wk);
  // Retrieve the weak reference
  WeakReference weakReference = (WeakReference)arr[0];
  MyObject mob = null;
  if( weakReference.IsAlive ){
    mob = (MyOBject)weakReference.Target;
  }
  if(mob==null){
    // Resurrect the object as it has been garbage collected
  }
  //continue because we have the object
}
于 2016-02-27T19:51:55.453 に答える