我正在运行一个parallel.foreach循环来遍历一个列表。每个列表项都包含一个api的标识符,我在循环中访问它。
我正在访问的api每分钟最多可以有225个请求,所以我想在220个项目之后暂停循环的执行,并在整个分钟过去后再次恢复它们。我尝试使用Thread.sleep(numMilliSeconds),但它似乎为每个进入睡眠或类似性质的线程启动了一个新线程。
这就是我现在使用的大致内容:
Parallel.ForEach(list, (currentItem) =>{
while(numRequestsLastMinute > 220 && DateTime.Now.Minute == lastDownloadTime.Minute)
{
var timeToPause = (60 - DateTime.Now.Second) * 1000;
Console.WriteLine("Thread pausing for" + timeToPause/100 + "seconds...");
Thread.Sleep(timeToPause);
Console.WriteLine("Thread resuming...");
}
if(DateTime.Now.Minute > lastDownloadTime.Minute)
{
lastDownloadTime = DateTime.Now;
numRequestsLastMinute = 0;
}
//send requests
}显然,Thread.Sleep不是解决这个问题的正确方法,但是有没有类似的构造可以在Parallel.Foreach循环中使用呢?
发布于 2020-06-04 06:17:40
我选择了批量解决方案。感谢你的建议,@Algef Almocera
int maxPerMinute = 220
while (list.Count > 0)
{
_ = Parallel.ForEach(batch, (currentItem) =>
{
});
batch = list.Take(maxPerMinute);
list = list.Skip(maxPerMinute).ToList();
Console.WriteLine(numItemsDone + " items downloaded");
if (DateTime.Now.Minute == lastDownloadTime.Minute)
{
var timeToPause = (60 - DateTime.Now.Second) * 1000;
Console.WriteLine(DateTime.Now.ToLongTimeString() + ": Thread pausing for " + timeToPause / 1000 + "seconds...");
Thread.Sleep(timeToPause);
Console.WriteLine(DateTime.Now.ToLongTimeString() + ": Thread resuming...");
}
lastDownloadTime = DateTime.Now;
}//end while发布于 2020-06-04 06:40:54
如果达到每分钟220个请求,您希望停止/暂停每个任务。这样他们每个人都可以到达它。所以每一个都应该检查它。如果发生这种情况,所有的任务都应该等待,直到有人释放它们。
因此,我将有一个队列来存储最后(0...220)个API调用的时间戳。和一个锁对象实例。
在任务内部-在一个永久循环中(带有取消中止条件):
- add/enqueue the current timestamp to the queue
-->所以带有锁的整个代码可以放在一个方法中,并从任务中调用
我没理解错吧,从UTC 0.000开始,在任何60秒或每分钟绝对时间内,您不应该超过225个请求?
PS:我也有类似的问题,但它被锁定在当地时区的一天-例如,Instagram只允许在当地时区的一天24小时内发布100张照片!所以从22:00到第二天凌晨2:00仍然可以发布200张图片,如果这两天没有其他图片发布的话。
https://stackoverflow.com/questions/62183081
复制相似问题