2016-04-21 81 views
1

假設我有很多CPU密集型任務被轉儲到默認調度程序中(全部一次運行,例如通過Task.RunTask.Factory.StartNew與默認調度程序)。每個任務都有一個延續。調度程序將啓動一些任務並將它們置於運行狀態。當這些任務完成後,調度程序就會在其隊列中混合使用原始任務和延續任務來安排時間並且必須在它們之間進行選擇。它如何優先考慮延續與運行更多的組織任務。特別是如果一個任務已經完成並且有一個延續,那麼這個延續在調度程序中優先於已經排隊的其他任務。任務與繼續調度

例如,假設sheduler運行多個(T1 ... Tn)排隊任務中的​​2個(T1 & T2)。當其中一個完成時,調度程序必須運行延續C1或可能決定啓動T3?無論如何,它會選擇哪種確定性的?調度器是否有可能選擇運行更多的任務,並且因此在T1的結束和其延續C1的開始之間可能會有相當大的延遲?

更新:我運行了一些示例代碼並添加了一個答案 - 但我仍然希望聽到這種觀察行爲是否有保證?

+0

哪個調度程序?你知道你可以實現你自己的?你的意思是默認的調度程序? – TomTom

+0

@TomTom問題已澄清。 – Ricibob

+0

看起來愚蠢的高度依賴於調度程序對任務的任何排序,除了通過延續執行並通過命令「await」執行的排序。我很想明確說明*不,這是不能保證的,因爲它會給實施帶來不必要的負擔,隨時都會受到束縛*,但是因爲我不是微軟的員工,所以我覺得不舒服這樣做。一般來說,儘管如此:在一個平行的詞中,如果你沒有同步事物,那麼事情就不會同步,除了偶然事件。 –

回答

0

所以我有樣品試了一下: - (?但是這是保證)

var continuations = new List<Task>(); 
for (int i = 0; i < 20; i++) { 
    int counter = i; 
    var continuation = Task.Run(() => { 
     Console.WriteLine($"T{counter}: Start."); 
     Thread.Sleep(500); 
     Console.WriteLine($"T{counter}: Complete."); 
    }).ContinueWith(t => { 
     Console.WriteLine($"C{counter}: Start."); 
     Thread.Sleep(50); 
     Console.WriteLine($"C{counter}: Complete."); 
    }); 
    continuations.Add(continuation); 
} 
Task.WaitAll(continuations.ToArray()); 

,它輸出以下暗示調度程序在啓動一個新的任務的延續優先

T1: Start. 
T2: Start. 
T3: Start. 
T0: Start. 
T1: Complete. 
T2: Complete. 
T3: Complete. 
C1: Start. 
C3: Start. 
T0: Complete. 
C0: Start. 
C2: Start. 
C1: Complete. 
T4: Start. 
C3: Complete. 
T5: Start. 
C0: Complete. 
T6: Start. 
C2: Complete. 
T7: Start. 
T4: Complete. 
C4: Start. 
T5: Complete. 
C5: Start. 
T6: Complete. 
C6: Start. 
T7: Complete. 
C7: Start. 
C4: Complete. 
C5: Complete. 
T9: Start. 
T8: Start. 
C7: Complete. 
T10: Start. 
C6: Complete. 
T11: Start. 
T8: Complete. 
C8: Start. 
T9: Complete. 
C9: Start. 
T11: Complete. 
C11: Start. 
T10: Complete. 
C10: Start. 
C9: Complete. 
C8: Complete. 
T13: Start. 
T12: Start. 
C11: Complete. 
T14: Start. 
C10: Complete. 

變化。這裏在啓動Task和註冊Continuation之間在調用線程上有額外的執行。

var continuations = new List<Task>(); 
for (int i = 0; i < 20; i++) { 
    int counter = i; 
    var task = Task.Run(() => { 
     Console.WriteLine($"T{counter}: Start."); 
     Thread.Sleep(500); 
     Console.WriteLine($"T{counter}: Complete."); 
    }); 
    Thread.Sleep(100); // Do some stuff before registering continuation. 
    var continuation = task.ContinueWith(t => { 
    Console.WriteLine($"C{counter}: Start."); 
     Thread.Sleep(150); 
     Console.WriteLine($"C{counter}: Complete."); 
    }); 
    continuations.Add(continuation); 
} 
Task.WaitAll(continuations.ToArray()); 

結果與上述情況相同,即對任務N的連續性給予其他排隊任務的優先級。

T0: Start. 
T1: Start. 
T2: Start. 
T3: Start. 
T0: Complete. 
C0: Start. 
T1: Complete. 
C1: Start. 
C0: Complete. 
T4: Start. 
T2: Complete. 
C2: Start. 
C1: Complete. 
T5: Start. 
T3: Complete. 
C3: Start. 
C2: Complete. 
T6: Start. 
C3: Complete. 
T7: Start. 
T4: Complete. 
C4: Start. 
T5: Complete. 
C5: Start. 
C4: Complete. 
T8: Start. 
T6: Complete. 
C6: Start. 
C5: Complete. 
T9: Start. 
T7: Complete. 
C7: Start. 
C6: Complete. 
T10: Start. 
C7: Complete. 
T11: Start. 
T8: Complete. 
C8: Start. 
T9: Complete. 
C9: Start. 
C8: Complete. 
T12: Start. 
T10: Complete. 
C10: Start. 
C9: Complete. 
T13: Start. 
T11: Complete. 
C11: Start. 
T14: Start. 
C10: Complete. 
T15: Start. 
C11: Complete. 
T16: Start. 
T12: Complete. 
C12: Start. 
T13: Complete. 
C13: Start. 
T14: Complete. 
C14: Start. 
C12: Complete. 
T17: Start. 
T15: Complete. 
C15: Start....... 

另一種變化。這裏所有的任務都先在Scheuler上排隊(並且可以預定運行),然後再註冊延續。

const int taskCount = 20; 
var tasks = new List<Task>(); 
for (int i = 0; i < taskCount; i++) { 
    int counter = i; 
    var task = Task.Run(() => { 
     Console.WriteLine($"T{counter}: Start."); 
     Thread.Sleep(500); 
     Console.WriteLine($"T{counter}: Complete."); 
    }); 
    tasks.Add(task); 
} 
Thread.Sleep(400); 
var continuations = new List<Task>(); 
for (int i = 0; i < taskCount; i++) { 
    int counter = i; 
    var continuation = tasks[i].ContinueWith(t => { 
     Console.WriteLine($"C{counter}: Start."); 
     Thread.Sleep(150); 
     Console.WriteLine($"C{counter}: Complete."); 
    }); 
    continuations.Add(continuation); 
} 
Task.WaitAll(continuations.ToArray()); 

結果與以前一樣 - 延續得到優先。

T0: Start. 
T2: Start. 
T3: Start. 
T1: Start. 
T1: Complete. 
T3: Complete. 
T0: Complete. 
T2: Complete. 
C2: Start. 
C0: Start. 
C3: Start. 
C1: Start. 
C2: Complete. 
C1: Complete. 
C0: Complete. 
C3: Complete. 
T7: Start. 
T4: Start. 
T6: Start. 
T5: Start. 
T6: Complete. 
T5: Complete. 
T7: Complete. 
T4: Complete. 
C6: Start. 
C5: Start. 
C7: Start. 
C4: Start. 
C7: Complete. 
T8: Start. 
C5: Complete. 
T9: Start. 
C6: Complete. 
T10: Start. 
C4: Complete. 
T11: Start. 
T8: Complete. 
C8: Start. 
T10: Complete. 
C10: Start. 
T9: Complete. 
C9: Start. 
T11: Complete. 
C11: Start. 
C8: Complete. 
T12: Start. 
C9: Complete. 
T13: Start. 
C10: Complete. 
T14: Start. 
C11: Complete. 
T15: Start. 
T14: Complete. 
T12: Complete. 
C12: Start. 
T13: Complete. 
C13: Start. 
C14: Start. 
T15: Complete. 
C15: Start. 
T16: Start. 
C12: Complete. 
C13: Complete. 
T18: Start. 
T17: Start. 
C14: Complete. 
T19: Start. 
C15: Complete. 
T16: Complete. 
C16: Start. 
T18: Complete. 
C18: Start. 
T17: Complete. 
T19: Complete. 
C19: Start. 
C16: Complete. 
C17: Start. 
C18: Complete. 
C19: Complete. 
C17: Complete.