के प्रारंभिक बिंदु के रूप में कार्य करने Memoization Wes Dyer's दृष्टिकोण लेते हैं:थ्रेड-सुरक्षित Memoization
public static Func<A, R> Memoize<A, R>(this Func<A, R> f)
{
var map = new Dictionary<A, R>();
return a =>
{
R value;
if (map.TryGetValue(a, out value))
return value;
value = f(a);
map.Add(a, value);
return value;
};
}
समस्या है, जब यह एक से अधिक थ्रेड से उपयोग कर रहा है, हम मुसीबत में पड़ सकते हैं:
Func<int, int> f = ...
var f1 = f.Memoize();
...
in thread 1:
var y1 = f1(1);
in thread 2:
var y2 = f1(1);
// We may be recalculating f(1) here!
आइए इससे बचने की कोशिश करें। map
पर लॉक करना:
public static Func<A, R> Memoize<A, R>(this Func<A, R> f)
{
var map = new Dictionary<A, R>();
return a =>
{
R value;
lock(map)
{
if (map.TryGetValue(a, out value))
return value;
value = f(a);
map.Add(a, value);
}
return value;
};
}
स्पष्ट रूप से एक भयानक विचार है क्योंकि यह हमें एक बार में कई अलग तर्क पर f1
की गणना करने से रोकता है है। a
पर लॉकिंग काम नहीं करेगा यदि a
में एक मान प्रकार है (और किसी भी दर पर एक बुरा विचार है, क्योंकि हम a
को नियंत्रित नहीं करते हैं और बाहरी कोड भी इसे लॉक कर सकता है)।
यहाँ दो विकल्प हैं मैं के बारे में सोच सकते हैं:
आलसी मूल्यांकन के लिए एक Lazy<T>
वर्ग मानते हुए (here देखें):
public static Func<A, R> Memoize<A, R>(this Func<A, R> f)
{
var map = new Dictionary<A, Lazy<R>>();
return a =>
{
Lazy<R> result;
lock(map)
{
if (!map.TryGetValue(a, out result))
{
result =() => f(a);
map.Add(a, result);
}
}
return result.Value;
};
}
या तुल्यकालन के लिए वस्तुओं की एक अतिरिक्त शब्दकोश रखते हुए:
public static Func<A, R> Memoize<A, R>(this Func<A, R> f)
{
var map = new Dictionary<A, R>();
var mapSync = new Dictionary<A, object>();
return a =>
{
R value;
object sync;
lock(mapSync)
{
if (!mapSync.TryGetValue(a, out sync))
{
sync = new object();
mapSync[a] = sync;
}
}
lock(map)
{
if (map.TryGetValue(a, out value))
return value;
}
lock(sync)
{
value = f(a);
lock(map)
{
map[a] = value;
}
return value;
}
};
}
कोई बेहतर विकल्प?
मैं यह कहना चाहूंगा कि यह एक उत्कृष्ट उत्तर है। धन्यवाद! –