定时方法调用-如何在时间到期时继续前进而不等待操作完成

本文关键字:继续 等待 操作 调用 方法 时间 定时 | 更新日期: 2023-09-27 18:03:06

我遇到了一个有趣的场景,我很难确定最佳解决方案是什么。

假设我有以下foreach-loop

Request[] requestArray = //Get Array of Request objects from somewhere
foreach(IRequest r in requestArray)
{
      var response = r.MakeRequest();
}
public class Request:IRequest
{
       public double IntervalInSeconds {get;set;} //Allowed Time To Complete Request
       public Response MakeRequest()
       {
             //Perform arbitrary operation, could be long or short running
       }
}
public interface IRequest
{
       Response MakeRequest();
}

问题:我需要做的是给每个请求一个IntervalInSeconds的值,指定该请求必须从MakeRequest()返回多长时间,然后我们继续。例如,如果我们将其设置为10,并且10秒过去了,我想继续前进,并完全忘记现有的MakeRequest()调用。

我已经研究了很多不同的方法来实现这一点,但不确定如何真正做到这一点。

定时方法调用-如何在时间到期时继续前进而不等待操作完成

很明显,在MakeRequest中正在完成的工作可能比IntervalInSeconds秒更长。如果MakeRequest必须同步运行,那么将该方法留在IntervalInSeconds中是非常困难的,除非在那里有一个循环,允许您非常定期地检查经过的时间。这可不是个好办法。

这里有一个快速和简单的方法来实现你的foreach循环,不涉及改变接口IRequest:

foreach(IRequest r in requestArray)
{
  var responseTask = Task.Run(r.MakeRequest);
  await Task.WhenAny(responseTask, Task.Delay(TimeSpan.FromSeconds(r.IntervalInSeconds));
}

这当然要求可以给这个foreach循环所在的方法一个Task(或void,但不要这样做)返回类型。

我可以想象更复杂的解决方案,其中MakeRequest照顾超时间隔本身,如果你需要它。

我使用了以下解决方案:

for(int i = 0; i < requestArray.Length;i++)
{
    var request = requestArray[i];
    var task = Task.Factory.StartNew<Response>(makeRequest);
    Task.WaitAny(new Task[]{task},request.IntervalInSeconds * 1000);
    if(task.Status == TaskStatus.RanToCompletion)
    {
         /*Done*/
         return task.Result;
    }      
    /*Keep Going*/
}