简体   繁体   English

暂停 Parallel.Foreach 循环

[英]Pausing a Parallel.Foreach loop

I am running a parallel.foreach loop to loop through a list.我正在运行一个 parallel.foreach 循环来遍历一个列表。 Each of the list items contains an identifier for an api, which I am accessing within the loop.每个列表项都包含一个 api 的标识符,我在循环中访问它。

The api I am accessing can has a maximum of 225 requests per minute, so I would like to pause execution of the loop after 220 items and resume them again once the full minute has passed.我正在访问的 api 每分钟最多有 225 个请求,所以我想在 220 个项目后暂停执行循环,并在整整一分钟后再次恢复它们。 I tried with Thread.sleep(numMilliSeconds), but it seems to start up a new thread for each one that goes to sleep or something of that nature.我尝试使用 Thread.sleep(numMilliSeconds),但它似乎为每个进入睡眠状态或类似性质的东西启动了一个新线程。

This is roughly what I am working with now:这大致是我现在正在使用的:

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

}

Clearly, the Thread.Sleep is not the right way to go about this, but is there a similar construct I can use within a Parallel.Foreach loop?显然,Thread.Sleep 不是 go 的正确方法,但是我可以在 Parallel.Foreach 循环中使用类似的构造吗?

I went with a batch solution.我选择了批处理解决方案。 Thanks for the tip, @Algef Almocera感谢您的提示,@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

You want to stop/pause each of the tasks, if 220 requests per minute is reached.如果达到每分钟 220 个请求,您想要停止/暂停每个任务。 So each of them could reach it.所以他们每个人都可以达到它。 So each of it should checking it.所以每个人都应该检查它。 If it happens, all the tasks should wait until somebody releases them.如果发生这种情况,所有任务都应该等到有人释放它们。

So I would have a queue for the timestamps of last (0...220) API calls.所以我会有一个队列来记录最后一次 (0...220) API 调用的时间戳。 And a lock object instance.和一个锁 object 实例。

Inside the task - in an forever loop (with cancel abort condition):在任务内部 - 在一个永远循环中(带有取消中止条件):

  • enter the lock, and inside do:进入锁,在里面做:
    • check the next entry in queue to dequeue, if older than 1 min delete检查队列中的下一个条目以出列,如果超过 1 分钟删除
    • do above point until no one older than 1 minute做到以上点,直到没有人超过 1 分钟
    • if still more then 220 entries如果还有超过 220 个条目
      • wait inside this task until the time is elapsed until the next queue entry is elapsed - so calculate the waiting time and wait在这个任务中等待,直到时间过去,直到下一个队列条目过去 - 所以计算等待时间并等待
      • remove the queue entry (now 1 is free - for this task)删除队列条目(现在 1 是空闲的 - 用于此任务)
    • add/enqueue the current timestamp to the queue将当前时间戳添加/排队到队列中
  • leave the lock离开锁
  • make the API call拨打 API 电话

--> so the whole code with the lock could be placed in a method and called from the task --> 所以带锁的整个代码可以放在一个方法中并从任务中调用

Do I understand you right, that you should not exceed 225 requests in any 60s or in every absolute minute starting with UTC 0.000 s?我是否理解正确,从 UTC 0.000 秒开始,您在任何 60 秒或每绝对分钟内不应超过 225 个请求?

PS: I had a similar problem, but that was locked to a day in local time zone - eg Instagram allowed once only to post 100 pictures in 24 hours of a day in local time zone: So from 22:00 to 02,00 next morning still 200 pictures could be posted. PS:我有一个类似的问题,但被锁定在当地时区的一天 - 例如 Instagram 只允许在当地时区一天 24 小时内发布 100 张照片:所以从 22:00 到 02,00 下一个早上仍然可以发布200张照片。 if no other ones were posted on both days.如果这两天都没有其他人发布。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM