![](/img/trans.png)
[英]How to limit number of HttpWebRequest per second towards a webserver?
[英]How would you limit the number of operations per second?
你如何限制每秒的操作次數?
假設我們必須將文件從一個位置復制到另一個位置,並且我們不希望每秒處理超過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;
}
}
}
但我需要一種更優雅和防彈的方式。
獲取開始時間,然后在循環中計算應當處理到當前時間的最大文件數,並在您處於領先狀態時進行休眠:
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
以避免每年發生兩次的令人討厭的跳躍。
另一種方法是測量操作所花費的時間,並在其余的時間段內休眠:
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<T> : IDisposable where T : class
{
readonly object _locker = new object();
readonly List<Thread> _workers;
readonly Queue<T> _taskQueue = new Queue<T>();
readonly Action<T> _dequeueAction;
readonly TimeSpan _throttleTimespan;
readonly Thread _workerThread;
/// <summary>
/// Initializes a new instance of the <see cref="SuperQueue{T}"/> class.
/// </summary>
/// <param name="millisecondInterval">interval between throttled thread invokation</param>
/// <param name="dequeueAction">The dequeue action.</param>
public ThrottledQueue(int millisecondInterval, Action<T> 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);
}
/// <summary>
/// Enqueues the task.
/// </summary>
/// <param name="task">The task.</param>
public void EnqueueTask(T task)
{
lock (_locker)
{
_taskQueue.Enqueue(task);
}
}
/// <summary>
/// Consumes this instance.
/// </summary>
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);
}
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
// Enqueue one null task per worker to make each exit.
EnqueueTask(null);
_workerThread.Join();
}
}
請注意,當您嘗試將處理的項目數限制為每秒500次時,上面的代碼仍會運行緊密循環,從而即使在不處理文件時也會對CPU造成負擔。
如果你想要一個真正的限制,你必須將你的邏輯改為定時器或事件驅動,或者使用其中一個Wait *方法來空閑你的進程,同時等待下一次做一些工作的機會。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.