2016-03-02 174 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