2010-03-11 39 views
4

我创建了一个简单的类,显示我正在尝试做什么,没有任何噪音。 随时打开我的代码。这就是我在这里发布的原因。有没有更好的方法来抑制高吞吐量的工作?

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(); 
      } 
     } 
    } 
} 
+0

您的代码缺少开始执行的公共方法。 – Vlad 2010-03-11 23:34:00

+0

@弗拉德 - 谢谢。 – ChaosPandion 2010-03-11 23:35:53

+0

根据文档(http://msdn.microsoft.com/en-us/library/system.threading.manualresetevent.aspx),您不需要保护'ManualResetEvent':它是线程安全的。 – Vlad 2010-03-11 23:39:10

回答

1

首先,我要彻底摆脱控制线程的,因为它的工作可以打电话给work()前轻松完成。

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

编辑:
根据该意见,我们的目标是在每个throttlePeriod蜱限制work()电话号码。我们可以通过在秒表中记下时间,比较它在throttleLimit工作操作和睡眠剩余时间之后做得更好。这样我们再次不需要计时器线程。

编辑:(去除,是不正确的)
编辑:
我们还可以做某种平衡:作为一个throttlePeriod内,我们计算多少时间做了work()拿,所以我们都可以估算HW多少时间剩余的work() s将要采取,并且在之间等待,每个两个work() s等于剩余时间的份额。这会使我们不能在分配的时间段开始时非常快地执行所有work(),可能会阻塞数据库。

+0

有趣的是,我应该如何在不使用计时器的情况下精确计时? – ChaosPandion 2010-03-12 00:20:45

+0

@ChaosPandion:你需要什么定时器?它似乎什么也没记录,只是清除了'totalProcessed'。 – Vlad 2010-03-12 00:32:13

+0

@ChaosPandion:你的工人代码在每个*迭代之后等待计时器 - 是你需要的吗? – Vlad 2010-03-12 00:33:11

0

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

事实上,为什么不把所有非UI线程放到较低的线程优先级上,以便您的应用程序始终保持响应?

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

+0

我正在限制访问数据库以防止锁定。我需要这份工作在高峰营业时间运行。 – ChaosPandion 2010-03-12 00:33:23