Ste*_*e B 6 c# performance thread-safety
我正在设计一个类库,它有一堆类型的方法"EnsureXXX".只要调用代码需要某些东西而不需要特定于参数的初始化,就会调用此方法的思想.它类似于EnsureChildControlsASP.Net 的方法,但有参数作为鉴别器.
例如:
public static class SomeUtilityClass {
public static void EnsureSomething(string arg1, int arg2, object arg3)
{
// Logic should be called once for each args combination
}
}
public class CallerClass
{
public void Foo()
{
SomeUtilityClass.EnsureSomething("mycustomerid", 4, myData.SomeProperty);
}
public void Foo2()
{
SomeUtilityClass.EnsureSomething("mycustomerid", 4, myData.SomeProperty);
}
}
Run Code Online (Sandbox Code Playgroud)
因为这样的模式将在几个地方重用并经常调用,所以我必须将性能作为目标.我还必须有一个线程安全的方法.
为此,我写了一个小实用程序类:
public sealed class CallHelper
{
private static readonly HashSet<int> g_YetCalled = new HashSet<int>();
private static readonly object g_SyncRoot = new object();
public static void EnsureOnce(Type type, Action a, params object[] arguments)
{
// algorithm for hashing adapted from http://stackoverflow.com/a/263416/588868
int hash = 17;
hash = hash * 41 + type.GetHashCode();
hash = hash * 41 + a.GetHashCode();
for (int i = 0; i < arguments.Length; i++)
{
hash = hash * 41 + (arguments[i] ?? 0).GetHashCode();
}
if (!g_YetCalled.Contains(hash))
{
lock (g_SyncRoot)
{
if (!g_YetCalled.Contains(hash))
{
a();
g_YetCalled.Add(hash);
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
消费代码如下所示:
public static class Program
{
static void Main()
{
SomeMethod("1", 1, 1);
SomeMethod("2", 1, 1);
SomeMethod("1", 1, 1);
SomeMethod("1", 1, null);
Console.ReadLine();
}
static void SomeMethod(string arg1, int arg2, object arg3)
{
CallHelper.EnsureOnce(typeof(Program), ()=>
{
Console.WriteLine("SomeMethod called only once for {0}, {1} and {2}", arg1, arg2, arg3);
}, arg1, arg2, arg3);
}
}
Run Code Online (Sandbox Code Playgroud)
正如预期的那样输出:
SomeMethod called only once for 1, 1 and 1
SomeMethod called only once for 2, 1 and 1
SomeMethod called only once for 1, 1 and
Run Code Online (Sandbox Code Playgroud)
我有一些与此方法相关的问题:
HashSet<int>和我的计算散列正确的方法是什么?我特别想知道null处理是否正确,以及我是否可以通过Action这种方式"哈希" 代表.提前致谢
这基本上是一个memoize,除了你的函数是无效的.但是,对输入参数进行比较的相同考虑因素仍然有效.
Wes Dyer讨论了如何在这篇文章中创建一个通用的多参数memoize.一般的想法是将所有参数都转换为匿名类型,并将其用作字典键.
关于使这个线程安全,请考虑.NET已经有并发集合.您不需要将非并发集合转换为并发集合; 只需使用提供的集合.
为了使这个方法适用于没有泄漏的实例方法,要么将WeakReference保留给实例,要么将memoizer的实例存储在实例本身中,无论哪种方法都适合您.
| 归档时间: |
|
| 查看次数: |
1685 次 |
| 最近记录: |