0

我正在玩,Interlocked.Increment想知道哪个呼叫计数器 impl。下面(基本上得到给定委托的调用次数)在高度并发的环境中正确地完成了它的工作(即线程安全)。

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;
        }
    }
}
4

1 回答 1

1

所有方法都是完全线程安全的,相对于_count.

但是,_count无论是否_func引发异常,这都会增加:

Interlocked.Increment(ref _count);
return _func(input);

_count仅当_func不引发异常时才会增加。

var result = _func(input);
Interlocked.Increment(ref _count);
return result;

这将与上述相同,但在多线程环境中性能较差,特别是因为任何时候只有一个线程能够调用_func

lock (_syncRoot)
{
    var result = _func(input);
    Count++;
    return result;
}

您选择哪个取决于您要测量的内容。

于 2020-06-23T10:34:59.913 回答