C#:使用Interlocked来统计delegate的调用次数是否正确?
C#: Is it right to use Interlocked to count the number of calls of a delegate?
我正在玩 Interlocked.Increment
并且想知道哪个调用计数器实现。下面(基本上获取给定委托的调用次数)在高度并发的环境中正常工作(即线程安全)。
public interface ICallCounter<in TInput, out TOutput>
{
public TOutput Invoke(TInput input);
public int Count { get; }
}
public class InterlockedPreCallCounter<TInput, TOutput> : ICallCounter<TInput, TOutput>
{
private readonly Func<TInput, TOutput> _func;
private int _count;
public int Count => _count;
public InterlockedPreCallCounter(Func<TInput, TOutput> func) => _func = func;
public TOutput Invoke(TInput input)
{
Interlocked.Increment(ref _count);
// What if there is an interruption / crash at some point here?
return _func(input);
}
}
public class InterlockedPostCallCounter<TInput, TOutput>
{
private readonly Func<TInput, TOutput> _func;
private int _count;
public int Count => _count;
public InterlockedPostCallCounter(Func<TInput, TOutput> func) => _func = func;
public TOutput Invoke(TInput input)
{
var result = _func(input);
Interlocked.Increment(ref _count);
return result;
}
}
public class LockCallCounter<TInput, TOutput> : ICallCounter<TInput, TOutput>
{
private readonly Func<TInput, TOutput> _func;
public int Count { get; private set; }
private readonly object _syncRoot = new object();
public LockCallCounter(Func<TInput, TOutput> func) => _func = func;
public TOutput Invoke(TInput input)
{
lock (_syncRoot)
{
var result = _func(input);
Count++;
return result;
}
}
}
相对于_count
.
,所有方法都是完全线程安全的
但是,无论 _func
是否抛出异常,这都会增加 _count
:
Interlocked.Increment(ref _count);
return _func(input);
仅当 _func
不抛出异常时,才会增加 _count
。
var result = _func(input);
Interlocked.Increment(ref _count);
return result;
这与上述相同,但在多线程环境中性能较差,特别是因为任何时候只有一个线程能够调用 _func
:
lock (_syncRoot)
{
var result = _func(input);
Count++;
return result;
}
您选择哪个取决于您要测量的内容。
我正在玩 Interlocked.Increment
并且想知道哪个调用计数器实现。下面(基本上获取给定委托的调用次数)在高度并发的环境中正常工作(即线程安全)。
public interface ICallCounter<in TInput, out TOutput>
{
public TOutput Invoke(TInput input);
public int Count { get; }
}
public class InterlockedPreCallCounter<TInput, TOutput> : ICallCounter<TInput, TOutput>
{
private readonly Func<TInput, TOutput> _func;
private int _count;
public int Count => _count;
public InterlockedPreCallCounter(Func<TInput, TOutput> func) => _func = func;
public TOutput Invoke(TInput input)
{
Interlocked.Increment(ref _count);
// What if there is an interruption / crash at some point here?
return _func(input);
}
}
public class InterlockedPostCallCounter<TInput, TOutput>
{
private readonly Func<TInput, TOutput> _func;
private int _count;
public int Count => _count;
public InterlockedPostCallCounter(Func<TInput, TOutput> func) => _func = func;
public TOutput Invoke(TInput input)
{
var result = _func(input);
Interlocked.Increment(ref _count);
return result;
}
}
public class LockCallCounter<TInput, TOutput> : ICallCounter<TInput, TOutput>
{
private readonly Func<TInput, TOutput> _func;
public int Count { get; private set; }
private readonly object _syncRoot = new object();
public LockCallCounter(Func<TInput, TOutput> func) => _func = func;
public TOutput Invoke(TInput input)
{
lock (_syncRoot)
{
var result = _func(input);
Count++;
return result;
}
}
}
相对于_count
.
但是,无论 _func
是否抛出异常,这都会增加 _count
:
Interlocked.Increment(ref _count);
return _func(input);
仅当 _func
不抛出异常时,才会增加 _count
。
var result = _func(input);
Interlocked.Increment(ref _count);
return result;
这与上述相同,但在多线程环境中性能较差,特别是因为任何时候只有一个线程能够调用 _func
:
lock (_syncRoot)
{
var result = _func(input);
Count++;
return result;
}
您选择哪个取决于您要测量的内容。