/// <summary> /// 定时添加令牌 /// </summary> private void TokenProcess() { int sleep = 1000 / MaxQPS; if (sleep == 0) { sleep = 1; //测试过只要不是while(true)且不sleep,就算sleep(1)CPU也没什么开销 } sleep += 1; //不能卡那么准 DateTime start = DateTime.Now; while (cancellationToken.Token.IsCancellationRequested == false) { lock (lockObject) { var isSuccess = limitedQueue.Enqueue(new object()); } if (DateTime.Now - start < TimeSpan.FromMilliseconds(sleep)) //如果因为等待lock而大于需要的sleep了那就不需要sleep可以直接开始放令牌 { int newSleep = sleep - (int)(DateTime.Now - start).TotalMilliseconds; if (newSleep >= 0) { Thread.Sleep(newSleep); //做损失时间补偿(等待造成的时间丢失补偿回来)例如sleep是500ms,等待花费了200ms,那么只需要sleep300ms就够了 } } start = DateTime.Now; } }
public bool RequestWithRetry(int retryCount) { if (retryCount < 0) { return(false); } RequestObject requestObject = new RequestObject(); bool isInBucket = false; while (retryCount != 0) { if (limitedQueue.Count < LimitSize && !isInBucket) { lock (lockObject) { if (limitedQueue.Count < LimitSize) { limitedQueue.Enqueue(requestObject); isInBucket = true; } } } if (requestObject.HasHandle) { return(true); } Thread.Sleep(System.Math.Max(0, limitedQueue.Count * 1000 / MaxQPS)); retryCount--; } return(false); }
private readonly object lockObject = new object();//用于加锁 /// <summary> /// 构造方法 /// </summary> /// <param name="maxQPS">最大QPS</param> /// <param name="limitSize">最大限制同时并发数</param> public TokenBucketLimitingService(int maxQPS, int limitSize) { MaxQPS = maxQPS; LimitSize = limitSize; limitedQueue = new LimitedQueue <object>(limitSize); for (int i = 0; i < limitSize; i++)//先放满令牌 { limitedQueue.Enqueue(new object()); } cancellationToken = new CancellationTokenSource(); task = Task.Factory.StartNew(new Action(TokenProcess), cancellationToken.Token); }