2016-03-02 170 views
2

我想要实现:的TaskScheduler用队列和超时问题

即排入指定的并行量任务和运行,而其他人在排队等待上手

任务调度。每个任务都有超时,在任务运行时开始计数,如果超过该时间则取消该任务,并引发在ContinueWith中处理的TimeoutException(或一些在其后立即运行的任务)。任务应该可以由用户取消。

我得到什么:

当第一个任务失败其他所有失败过瞬间。

这是我的任务计划程序的完整代码(从MSDN有一些修改拍摄):

http://pastebin.com/KSMbDTH5。 (有问题的功能上线161)

下面是使用例子:

var taskTokens = new List<CancellationToken>(); 
var factory = new TaskScheduleFactory(new ParallelOptions() { MaxDegreeOfParallelism = 1 }); //for the purpose of testing, supposed to work and with higher values 
for (var i = 0; i < 10; i++) 
{ 
    //TaskScheduleFactory.cs, line 161 
    var taskToken = factory.Add(
     (token) => //Task 
     { 
      Console.WriteLine("Start"); 
      Thread.Sleep(5000); 
      if (token.IsCancellationRequested) return; //Cancelled by timeout 
      Console.WriteLine("This should not print"); 
     }, 
     (task) => //ContinueWith 
     { 
      if (task.IsFaulted) 
      { 
       Console.WriteLine("Fail"); 
      } 
      else if (!task.IsCompleted) 
      { 
       Console.WriteLine("Not completed"); 
      } 
      else Console.WriteLine("Done"); 
     }, 
     2000 //Timeout 
    ); 
    taskTokens.Add(taskToken); 
} 

它是如何工作的:(我们强迫超时事件2秒后这样既不任务将完成)

对于MaxDegreeOfParallelism = 1:

Start; 
(Wait 2sec) 
Fail; 
Start; 
(Wait 2sec) 
Fail; 
.... 

为MaxDegreeOfParallelism = 2:

Start; 
Start; 
(Wait 2sec) 
Fail; 
Fail; 
Start; 
Start; 
(Wait 2sec) 
Fail; 
Fail; 
.... 

它是如何工作的:

Start; 
(Wait 2sec) 
Fail; 
Fail; 
Fail; 
Fail; 
... 

(用于MaxDegreeOfParallelism = 1,其余的都是乱七八糟太)

注:这是我与TPL的第一个步骤,所以从我身边原谅任何愚蠢

回答

1

不完美的解决方案,但我能想到的最好的:

public CancellationTokenSource Add(Action<CancellationToken> action, Action<Task> callback, int timeoutInMilliseconds) 
{ 
    var cts = new CancellationTokenSource(); 
    Instance.StartNew(() => 
    { 
     cts.CancelAfter(timeoutInMilliseconds); 
     var task = Task.Factory.StartNew(() => action(cts.Token), cts.Token, TaskCreationOptions.AttachedToParent|TaskCreationOptions.LongRunning, TaskScheduler.Default); 
     try 
     { 
      task.Wait(timeoutInMilliseconds, cts.Token); 
     } 
     catch (OperationCanceledException) { } 
     callback(task); 
    }, cts.Token); 
    return cts; 
} 

简而言之:当任务从队列中开始它的默认任务调度程序创建子任务(因为其他人会只是入队),然后我们等待一定的时间并调用回调函数。不知道这是多么糟糕。

2

Add你叫.TimeoutAfter(timeoutInMilliseconds, cts)。这意味着超时将在您创建任务时立即开始。我认为你的意图是在任务开始执行时才开始超时。

由于第一个任务需要比超时更长的时间,因此所有其他任务在轮到时都已超时。

+0

好点。我将TimeoutAfter和ContinueWith移动到了动作的主体中,但仍然很难使其正常工作。你能详细说明如何解决它吗? – Arvigeus

+0

你已经写了一些非常高级的代码。我认为这将达到你解决:)类似的东西应该工作:var workTask = Instance.StartNew(()=> {cts.CancelAfter(timeoutInMilliseconds); action(cts.Token);},cts。令牌); var resultTask = Task.WhenAll(workTask,cts.Token);'。这可能会在你不喜欢的状态下完成'resultTask'(它将最终取消我认为的)。如果你想要更多的控制,你可以用TaskCompletionSource来实现任何完成行为。 – usr

+0

呵呵,我之前提到我从MSDN的例子中复制了大部分代码。我写的唯一部分是实际上并不工作的部分。谢谢您的帮助!我将离开几天,所以需要一些时间来验证它并将其标记为答案(除非我的愚蠢阻止​​我正确实施它)。欢呼,祝你有个美好的一周! – Arvigeus