هل هذا التخزين المؤقت وظيفة العمل كيف اعتقد انه يفعل ؟

StackOverflow https://stackoverflow.com/questions/707909

سؤال

لقد مبدئيا كتب هذه الطريقة:

public static Func<T> WeakCacheFor<T>( Func<T> provider ) where T: class
{
    var cache = new WeakReference(null);
    return () => {
        var x = (T)cache.Target;
        if( x == null )
        {
            x = provider();
            cache.Target = x;
        }
        return x;
    };
}

لذا قليلا من الخلفية:

لدي بعض مهزار إرث الأساليب التي تبدو مثل هذا:

var id = GetDatabaseId();
if(a){
    var data = GetLoader().Init(id).GetData(); // expensive!
    // do stuff with data
}
if(b){
    // don't load data
}
... lots more variations, some contain GetLoader().Init(id).GetData(); some don't....

قدراتي الحل هو أن تفعل هذا:

var id = GetDatabaseId();
var loadData = WeakCacheFor(() => GetLoader().Init(id).GetData());
if(a){
    var data = loadData();
    // do stuff with data
}
if(b){
    // don't load data
}
... lots more variations, some contain loadData(); some don't....

أفكاري حول هذا:

  • لا تحتاج إلى ذاكرة التخزين المؤقت خارج نطاق هذا استدعاء الأسلوب فلا بأس إذا كان GC يجمع عليه بمجرد إرجاع الأسلوب
  • إذا كان رمز يأخذ الطريق التي لا تحتاج إلى تحميل البيانات ضرب لن يتم تكبدها
  • إذا أنها لا تحتاج البيانات سوف يكون مؤقتا في إشارة ضعيفة إذا كان هناك حاجة مرة أخرى.
  • إذا كان GC لا جمع في منتصف الطريق, لا يهم كما أنها سوف مجرد الحصول على إعادة تحميلها.

أسئلتي:

  1. سيكون هذا العمل فعلا ؟ - هل هناك شيء فاتني في WeakCacheFor الطريقة التي قد تتسبب في إشارة قوية إلى inadvertenly ؟
  2. هل أنا ذكي جدا من أجل مصلحتي الخاصة ؟ - يجب أن تتحمل ضرب ذاكرة التخزين المؤقت البيانات في وضعها الطبيعي المتغير المحلي حتى لو انها ليست في حاجة ؟

وأظن أني قد يكون ذكيا جدا ، ولكن حتى لو كنت أنا ، هل هذا يبدو أن أي شخص آخر مثل الحل الذي يمكن أن يكون مفيد في حالات أخرى??

تحديث:تعديل وظيفة بسبب على ما يبدو لا يمكنك الثقة .IsAlive

تحديث:أدركت أن عاد Func سوف تخرج من نطاق في نهاية الأسلوب ، لذلك أنا لا تحتاج إلى weakref في العادي ref سوف تعمل على ما يرام.كنت تعاني من حالة "لا يمكن رؤية الغابة من الأشجار" أعتقد.

هل كانت مفيدة؟

المحلول

أنا لا أرى أي نقطة في استخدام ضعف الإشارة.وبمجرد الانتهاء من تحميل البيانات لا يكاد يكون هناك أي سبب رميها بعيدا حتى كنت متأكدا من أنه ليس من المفيد أكثر من ذلك.

ما كنت تقوم بتنفيذ هو الاختلاف من تحميل كسول نمط.التمسك نمط بسيط و مجرد استخدام منتظم الإشارة إلى البند:

public static Func<T> LazyLoad<T>(Func<T> provider) where T : class {
   T item = null;
   return () => {
      if (item == null) {
         item = provider();
      }
      return item;
   };
}

(و نصيحة صغيرة:كنت تستخدم var الكلمة كثيرا.)

نصائح أخرى

بعض الملاحظات العامة:

  1. الحل الخاص بك (كما) ليست موضوع آمنة.
  2. أنها ليست مصممة للعمل مع IDisposable الكائنات.

المناقشة التالية في الاعتبار:

foo = WeakCacheFor<Foo>(() => CreateFoo());

حالة رقم 1:باستخدام فو طويلة المعيشة متغير (مثلعضو طويلة معيشة الطبقة ، أو عالمي متغير)

الحل المنطقي هنا.المتغير سيتم إنشاء عند الحاجة ، ودمرت عند النظام يحرر الموارد خلال GC.

ولكن لاحظ أنه إذا فو الوقت مكلفة ولكن الذاكرة رخيصة من المحتمل فمن المنطقي لاستخدام نمط المفرد بدلا وتحميله مرة واحدة طوال مدة التطبيق ؟

الحالة رقم 2.باستخدام فو حسب متغير محلي.

في هذه الحالة فمن الأفضل استخدام نمط المفرد أعتقد.النظر في مثل هذا المثال:

static void Main(string[] args)
{
    MethodA(5, 7);
    MethodA(8, 9);
}

static void MethodA(int a, int b)
{
    var foo = WeakCacheFor<Foo>(() => new Foo());

    if (a > 3)
    {
        Use(foo);

        if (a * b == 35)
        {
            GC.Collect(); // Simulate GC
            Use(foo);
        }
        else if(b % 6 == 2)
        {
            Use(foo);
        }
    }
}

فو سيتم إنشاء 3 مرات.و 2 مرات إذا كنت التعليق "محاكاة GC" خط.أيضا لا يمكنك استخدام هذا IDisposable classess.

الآن دعونا نحاول المفرد:

static void MethodA(int a, int b)
{
    using (var foo = new MySingleton<Foo>(() => new Foo()))
    {
        if (a > 3)
        {
            Use(foo);

            if (a * b == 35)
            {
                GC.Collect(); // Simulate GC
                Use(foo);
            }
            else if (b % 6 == 2)
            {
                Use(foo);
            }
        }
    }
}

كما يمكنك أن ترى رمز تقريبا لم تتغير ، ولكن الآن نحن فقط الحصول على 2 مكالمات فو المنشئ و IDisposable الدعم.

الخام المفرد التنفيذ:

class MySingleton<T> : IDisposable
    where T : class
{
    private T _value;
    private Func<T> _provider;

    public MySingleton(Func<T> provider)
    {
        _provider = provider;
    }

    public T Get()
    {
        if (_value == null)
        {
            _value = _provider();
        }

        return _value;
    }

    #region IDisposable Members

    public void Dispose()
    {
        if(_value == null)
            return;

        IDisposable disposable = _value as IDisposable;

        if(disposable != null)
            disposable.Dispose();
    }

    #endregion
}

وبقية التعليمات البرمجية:

class Foo : IDisposable
{
    public void Dispose() {}
}

static void Use(MySingleton<Foo> foo)
{
    foo.Get();
}

static void Use(Func<Foo> foo)
{
    foo();
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top