是否有更好的方法来限制高吞吐量的工作?

时间:2010-03-11 23:27:29

标签: c# .net synchronization

我创建了一个简单的类,它显示了我没有任何噪音的尝试。 随意抨击我的代码。这就是我在这里发布的原因。

public class Throttled : IDisposable
{
    private readonly Action work;
    private readonly Func<bool> stop;
    private readonly ManualResetEvent continueProcessing;
    private readonly Timer throttleTimer;
    private readonly int throttlePeriod;
    private readonly int throttleLimit;
    private int totalProcessed;

    public Throttled(Action work, Func<bool> stop, int throttlePeriod, int throttleLimit)
    {
        this.work = work;
        this.stop = stop;
        this.throttlePeriod = throttlePeriod;
        this.throttleLimit = throttleLimit;
        continueProcessing = new ManualResetEvent(true);
        throttleTimer = new Timer(ThrottleUpdate, null, throttlePeriod, throttlePeriod);
    }

    public void Dispose()
    {
        throttleTimer.Dispose();
        ((IDisposable)continueProcessing).Dispose();
    }

    public void Execute()
    {
        while (!stop())
        {
            if (Interlocked.Increment(ref totalProcessed) > throttleLimit)
            {
                lock (continueProcessing)
                {
                    continueProcessing.Reset();
                }
                if (!continueProcessing.WaitOne(throttlePeriod))
                {
                    throw new TimeoutException();
                }
            }

            work();
        }
    }

    private void ThrottleUpdate(object state)
    {
        Interlocked.Exchange(ref totalProcessed, 0);
        lock (continueProcessing)
        {
            continueProcessing.Set();
        }
    }
}

最新代码

public class Throttled
{
    private readonly Func<bool> work;
    private readonly ThrottleSettings settings;
    private readonly Stopwatch stopwatch;
    private int totalProcessed;

    public Throttled(Func<bool> work, ThrottleSettings settings)
    {
        this.work = work;
        this.settings = settings;
        stopwatch = new Stopwatch();
    }

    private void Execute()
    {
        stopwatch.Start();
        while (work())
        {
            if (++totalProcessed > settings.Limit)
            {
                var timeLeft = (int)(settings.Period - stopwatch.ElapsedMilliseconds);
                if (timeLeft > 0)
                {
                    Thread.Sleep(timeLeft);
                }
                totalProcessed = 0;
                stopwatch.Reset();
                stopwatch.Start();
            }
        }
    }
}

2 个答案:

答案 0 :(得分:1)

首先,我会彻底摆脱控制线程,因为在调用work()之前可以轻松完成其工作。

然后,我将使工作线程与主线程不同,从而解除主线程的阻塞以执行其他任务。接下来,我将添加一个取消处理的函数,这可能会设置一个标志来检查工作线程。

编辑:
根据评论,我们的目标是在每个work()刻度期间限制throttlePeriod次呼叫的数量。我们可以通过在秒表中记录时间,在throttleLimit工作操作之后进行比较以及休眠剩余时间来更好地做到这一点。这样我们再次不需要计时器线程。

编辑:(删除,不正确)
编辑:
我们甚至可以进行某种平衡:在throttlePeriod范围内,我们计算work()所花费的时间,因此我们可以估算剩下的work()所花费的时间多少采取,并在每个两个work()之间等待剩余时间的相等份额。这将使我们不会在分配的时间段开始时非常快地执行所有work(),可能会阻止数据库。

答案 1 :(得分:0)

为什么要油门?为什么Sleep()什么时候可以把一个线程置于较低的优先级并让它吸收所有未使用的CPU周期,尽可能快地完成工作而不中断任何更高优先级的工作?

事实上,为什么不将所有非UI线程放在较低线程优先级上,以便您的应用程序保持整体响应?

这里唯一需要注意的是,如果您正在进行IO操作 - 需要限制磁盘访问以保证其他所有内容顺利运行。