你如何限制每秒的操作次数?

你如何限制每秒的操作次数?

假设我们必须将文件从一个位置复制到另一个位置,并且我们不希望每秒处理超过5个文件。

请看看我在做什么

private static string currentStamp; private static int processedInCurrentStamp = 0; private static void Main(string[] args) { currentStamp = DateTime.Now.ToString("{0:d/M/yyyy HH:mm:ss}"); Run(); } private static void Run() { for (int i = 0; i < Int32.MaxValue; i++) { string s = DateTime.Now.ToString("{0:d/M/yyyy HH:mm:ss}"); if (currentStamp.Equals(s)) { if (processedInCurrentStamp < 5) { ProcessItem(); processedInCurrentStamp++; } } else { Console.WriteLine("{0} ::: {1}", currentStamp, processedInCurrentStamp); currentStamp = s; processedInCurrentStamp = 0; } } } 

但我需要一种更优雅,更防弹的方式。

获取开始时间,然后在循环中计算应当处理到当前时间的最大文件数,并在您处于领先状态时进行hibernate:

 DateTime start = DateTime.UtcNow; int i = 1; while (i <= 100) { int limit = (int)((DateTime.UtcNow - start).TotalSeconds * 5.0); if (i <= limit) { Console.WriteLine(i); i++; } else { Thread.Sleep(100); } } 

这样,如果某些操作需要更长时间,代码将会赶上。 如果你一秒钟只进行三次操作,那么下一秒就可以进行七次操作。

请注意,我使用UtcNow而不是Now来避免每年发生两次的令人讨厌的跳跃。

编辑:

另一种方法是测量操作所花费的时间,并在其余的时间段内hibernate:

 for (int i = 1; i <= 100; i++ ) { DateTime start = DateTime.UtcNow; Console.WriteLine(i); int left = (int)(start.AddSeconds(1.0 / 5.0) - DateTime.UtcNow).TotalMilliseconds; if (left > 0) { Thread.Sleep(left); } } 

我会创建一个简单的方法,一次处理五个文件,并使用计时器每秒调用一次。

Sumee

您可以使用受限制的生产者/消费者队列。 它会有一个后台线程,它以一定的间隔运行,处理你的文件。 您可以在文件名到达时将其排队,并且受限制的出列操作(Action)将出列。 这是我的意思的一个例子:

  public class ThrottledQueue : IDisposable where T : class { readonly object _locker = new object(); readonly List _workers; readonly Queue _taskQueue = new Queue(); readonly Action _dequeueAction; readonly TimeSpan _throttleTimespan; readonly Thread _workerThread; ///  /// Initializes a new instance of the  class. ///  /// interval between throttled thread invokation /// The dequeue action. public ThrottledQueue(int millisecondInterval, Action dequeueAction) { _dequeueAction = dequeueAction; // Create and start a separate thread for each worker _workerThread = new Thread(Consume) { IsBackground = true, Name = string.Format("ThrottledQueue worker") }; _workerThread.Start(); _throttleTimespan = new TimeSpan(0,0,0,0,millisecondInterval); } ///  /// Enqueues the task. ///  /// The task. public void EnqueueTask(T task) { lock (_locker) { _taskQueue.Enqueue(task); } } ///  /// Consumes this instance. ///  void Consume() { while (true) { T item = default(T); lock (_locker) { Monitor.Wait(_locker, _throttleTimespan); if (_taskQueue.Count != 0) item = _taskQueue.Dequeue(); } if (item == null) return; // run actual method _dequeueAction(item); } } ///  /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. ///  public void Dispose() { // Enqueue one null task per worker to make each exit. EnqueueTask(null); _workerThread.Join(); } } 

请注意,当您尝试将处理的项目数限制为每秒500个时,上面的代码仍会运行紧密循环,因此即使不处理文件也会对CPU造成负担。

如果你想要一个真正的限制,你必须将你的逻辑改为定时器或事件驱动,或者使用其中一个Wait *方法来空闲你的进程,同时等待下一次做一些工作的机会。