0

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

假设我有以下 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() 调用。

我研究了很多不同的方法可以用来实现这一点,但不知道如何真正做到这一点。

4

2 回答 2

1

很明显,在 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 会自行处理超时间隔。

于 2013-03-08T19:30:18.790 回答
0

我使用了以下解决方案:

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*/
}
于 2013-03-08T21:55:34.190 回答