在我的.NET程序中,我想计算一段代码被击中的次数。为了使它更具挑战性,我的代码通常在多个线程中执行,我无法控制线程的创建/销毁(并且不知道它们何时被创建)......它们甚至可以被合并。说:
class Program
{
static int counter = 0;
static void Main(string[] args)
{
Stopwatch sw = Stopwatch.StartNew();
Parallel.For(0, 100000000, (a) =>
{
Interlocked.Increment(ref counter);
});
Console.WriteLine(sw.Elapsed.ToString());
}
}
由于性能计数器和方法遭遇了很多次,我想使用正常的'变量与原子/互锁整数形成对比。因此,我的第二次尝试是将threadlocal存储与IDisposable结合使用以加快速度。因为我无法控制创建/销毁,所以我必须跟踪存储变量:
class Program
{
static int counter = 0;
// I don't know when threads are created / joined, which is why I need this:
static List<WeakReference<ThreadLocalValue>> allStorage =
new List<WeakReference<ThreadLocalValue>>();
// The performance counter
[ThreadStatic]
static ThreadLocalValue local;
class ThreadLocalValue : IDisposable
{
public ThreadLocalValue()
{
lock (allStorage)
{
allStorage.Add(new WeakReference<ThreadLocalValue>(this));
}
}
public int ctr = 0;
public void Dispose()
{
// Atomic add and exchange
int tmp = Interlocked.Exchange(ref ctr, 0); // atomic set to 0-with-read
Interlocked.Add(ref Program.counter, tmp); // atomic add
}
~ThreadLocalValue()
{
// Make sure it's merged.
Dispose();
}
}
// Create-or-increment
static void LocalInc()
{
if (local == null) { local = new ThreadLocalValue(); }
++local.ctr;
}
static void Main(string[] args)
{
Stopwatch sw = Stopwatch.StartNew();
Parallel.For(0, 100000000, (a) =>
{
LocalInc();
});
lock (allStorage)
{
foreach (var item in allStorage)
{
ThreadLocalValue target;
if (item.TryGetTarget(out target))
{
target.Dispose();
}
}
}
Console.WriteLine(sw.Elapsed.ToString());
Console.WriteLine(counter);
Console.ReadLine();
}
}
我的问题是:我们能更快和/或更漂亮吗?
答案 0 :(得分:1)
您需要的是一个线程安全,无阻塞,volatile,static变量来为您执行计数。
非常感谢,.NET框架提供了管理方式来执行您想要的任务。
对于初学者,您需要一个易失性的静态变量作为计数器。声明它(所有线程都可以访问它):
public static volatile int volatileCounter;
其中 static 表示这是一个类而不是实例成员, volatile 可防止缓存错误发生。
接下来,您将需要一个以线程安全且无阻塞的方式递增它的代码。如果您不希望您的计数器超出int变量的限制(很可能),您可以使用Interlocked class来表示:
Interlocked.Increment(ref yourInstance.volatileCounter);
interlocked class将保证您的增量操作将原子,因此没有竞争条件可能导致错误结果,并且它也是以非常重的方式进行非阻塞{这里涉及{3}}和线程阻塞。