首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >并发节流

并发节流
EN

Stack Overflow用户
提问于 2012-01-27 18:23:31
回答 2查看 385关注 0票数 1

下面是一个简单的并发限制和相关测试。它不能经常观察到超过指定的并发性,但我不确定为什么?

代码语言:javascript
复制
[TestFixture]
public class ConcurrencyThrottleTests
{
    [Test]
    public void ThrottleTest()
    {
        var throttle = new ConcurrencyThrottle(2);
        var maxReg = new MaxRegister();
        var threadPool = new SmartThreadPool();

        var state = new DoWorkState {Throttle = throttle, MaxRegister = maxReg};
        var workItemResults = new List<IWaitableResult>();

        for (int i = 0; i < 1000; i++)
            workItemResults.Add(threadPool.QueueWorkItem(DoWork, state));

        SmartThreadPool.WaitAll(workItemResults.ToArray());

        Assert.IsTrue(maxReg.MaxValue <= 2);
    }

    public void DoWork(object state)
    {
        var doWorkState = (DoWorkState)state;

        doWorkState.Throttle.Enter();
        try
        {
            doWorkState.MaxRegister.Increment();

            Thread.Sleep(10);

        }
        finally
        {
            doWorkState.MaxRegister.Decrement();
            doWorkState.Throttle.Exit();
        }
    }

    public class DoWorkState
    {
        public IConcurrencyThrottle Throttle { get; set; }
        public MaxRegister MaxRegister { get; set; }
    }

    public class ConcurrencyThrottle : IConcurrencyThrottle
    {
        private readonly int _max;
        private readonly object _lock = new object();
        private readonly MaxRegister _register = new MaxRegister();

        public ConcurrencyThrottle(int max)
        {
            _max = max;
        }

        public void Exit()
        {
            lock (_lock)
            {
                _register.Decrement();

                Monitor.Pulse(_lock);
            }
        }

        public void Enter()
        {
            lock (_lock)
            {
                while (_register.CurrentValue == _max)
                    Monitor.Wait(_lock);

                _register.Increment();
            }
        }
    }

    public class MaxRegister
    {
        public int MaxValue { get; private set; }
        public int CurrentValue { get; private set; }

        public void Increment()
        {
            MaxValue = Math.Max(++CurrentValue, MaxValue);
        }

        public void Decrement()
        {
            CurrentValue--;
        }
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-01-27 18:47:52

问题是,尽管并发被限制为两个,但您仍然在可调节的代码中使用非线程安全对象( MaxRegister):

代码语言:javascript
复制
doWorkState.Throttle.Enter();
try
{
    doWorkState.MaxRegister.Increment();
    Thread.Sleep(10);
}
finally
{
    doWorkState.MaxRegister.Decrement();
    doWorkState.Throttle.Exit();
}

MaxRegister.IncrementMaxRegister.Decrement不涉及锁定,也不使用原子Interlocked操作,这是确保它们安全所必需的。

MaxRegister.Decrement中使用Interlocked.Decrement就足够了,而Increment则更难,因为您有两个值。您可以在CurrentValue上使用Interlocked.Increment,记住结果,然后在必要时自动使用CompareExchange来增加MaxValue。或者只对这两个操作都使用锁:)

请注意,为了使用Interlocked,您需要避免使用自动实现的属性,因为互锁方法有ref参数。

票数 1
EN

Stack Overflow用户

发布于 2012-01-27 18:57:13

在我看来,对于"ConcurrencyThrottle.Enter“的初学者来说,你有:

代码语言:javascript
复制
while (_register.CurrentValue == _max) 

如果CurrentValue大于max,它就会中断,所以也许你应该这样做:

代码语言:javascript
复制
while (_register.CurrentValue >= _max) 

其次,你有

代码语言:javascript
复制
var maxReg = new MaxRegister();

在你的状态方法中,然后在你的“ThrottleTest”变量中赋值和操作-然而,这个变量与在ConcurrencyThrottle类中声明的变量完全无关。因此,递增或递减"doWorkState“中的值对您在"ConcurrencyThrottle.Enter”中测试的值没有任何影响。

我很想把ConcurrencyThrottle最大化为一个单例,并如下所示:

代码语言:javascript
复制
public class ConcurrencyThrottle : IConcurrencyThrottle
{
    private int Max { get; set;}
    private static object _lock = new object();
    private static object _concurrencyLock = new object();
    public static MaxRegister Register { get; set; }
    private static volatile _Default;

    private ConcurrencyThrottle()
    {
        Register = new MaxRegister
        {
            CurrentValue = 0,
            MaxValue = 2
        };
    }

    public static ConcurrencyThrottle Default
    {
        get
        {
            lock (_lock)
            {
                if(_Default == null)
                {
                    _Default = new ConcurrencyThrottle();
                }

                return_Default;
            }
        }
    }

    public void Enter() 
    { 
        lock (_concurrencyLock) 
        { 
            while (Register.CurrentValue == _max) 
                Monitor.Wait(_concurrencyLock); 

            Register.Increment(); 
        } 
    } 

    etc etc

这显然只是一个建议,但据我所知,您ConcurrencyThrottle中的MaxRegister与您在"DoWork“中操作的are无关。

希望对大家有帮助,快乐编码!

干杯,

克里斯。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9031843

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档