Планирование задачи против продолжения

Предположим, у меня много задач с интенсивным использованием ЦП, которые выводятся в планировщике по умолчанию (все выполняются одновременно, например, через Task.Run или же Task.Factory.StartNew с планировщиком по умолчанию). Каждое задание имеет продолжение. Планировщик запустит несколько задач и переведет их в рабочее состояние. Когда эти задачи завершаются, планировщик имеет в своем списке смесь исходных задач и задач продолжения для планирования, и ему приходится выбирать между ними. Как это расставляет приоритеты для продолжения по сравнению с выполнением большего количества задач org. В частности, если задача выполнена и у нее есть продолжение, это продолжение получает приоритет в планировщике над другими задачами, которые уже поставлены в очередь.

Например, предположим, что шедулер запускает 2 (T1 и T2) из ​​множества (T1...Tn) поставленных в очередь задач. Когда один из этих этапов будет завершен, планировщик обязательно запустит продолжение C1 или решит запустить T3? Это в любом случае детерминистическое, что он выберет? Возможно ли, что планировщик выберет выполнить больше задач и что для этого может быть значительная задержка между концом T1 и началом его продолжения C1?

Обновление: я запустил пример кода и добавил ответ - но я все еще хотел бы услышать, гарантировано ли это наблюдаемое поведение?

1 ответ

Итак, я попробовал это с образцом:

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.

Вариация Здесь есть дополнительное выполнение в вызывающем потоке между запуском Задачи и регистрацией Продолжения.

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.......

Еще один вариант. Здесь ВСЕ задачи ставятся в очередь в планировщике первыми (и могут быть запланированы для выполнения) ДО регистрации продолжений.

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.
Другие вопросы по тегам