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

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

public class Throttled : IDisposable { private readonly Action work; private readonly Func 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 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 work; private readonly ThrottleSettings settings; private readonly Stopwatch stopwatch; private int totalProcessed; public Throttled(Func 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(); } } } } 

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

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

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

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

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

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

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