Заранее извиняюсь за столь длинный вопрос. Разбираюсь c Task и TaskScheduler. Я не уверен, что я правильно понимаю смысла существования TaskScheduler. Как я вижу ситуацию с ним, т.к TaskScheduler является абстрактным, мы не можем создавать его напрямую, поэтому у нас есть следующие два способа его создания:
TaskScheduler и переопределить метод QueueTask
который должен запускать задачу отложено;TaskScheduler с помощью
TaskScheduler.Default.Потом экземпляр TaskScheduler мы отправляем в конструктор TaskFactory и после этого мы на экземпляре TaskFactory вызывается метод StartNew, в который мы передаем нашу отложенную задачу. И тут StartNew вызывает QueueTask (метод который находится в TaskScheduler и который мы возможно переопределили) и вот QueueTask задает отложенный вызов нашей задачи которую мы передали в StartNew. Вот на основе этого возникли следующие ВОПРОСЫ:
TaskScheduler вовсе никакой не планировщик задач, а просто прослойка
между запускам задачи и ее началом выполнения. Он просто делает так,
что бы StartNew (метод TaskFactory) запускал не саму задачу, а
метод QueueTask в котором я сам должен сделать всю логику
планирования. Получается он не имеет какую-то внутреннюю логику по
запуску задач отложено. Нет, я понимаю, он имеет потому, что я сам
ее написал в методе QueueTask, но по факту TaskScheduler это лишь
механизм внедрения МОЕГО собственного планировщика. Я правильно
понимаю или же я чего-то не знаю?TaskScheduler через TaskScheduler.Default какая
реализация будет у QueueTask? Как я понял он просто сразу запускает
задачу...ThreadPool.RegisterWaitForSingleObject
т.е все, мы отправили туда callback. Второй раз мы уже не можем
запустить эту задачу, зачем нам ее хранить? Я лишь предполагаю, что
мы ее храним лишь для возможного контроля ее, до запуска.Task -- это абстракция задачи, которая
ничего не говорит о том, где и кем будет выполнена задача. Этим как
раз управляет TaskScheduler. Как вы верно заметили, класс
TaskScheduler является абстрактным, а значит, конкретная логика
заключена в его наследниках. А вот TaskFactory (и метод
Task.Run()) -- это действительно прослойка между задачей и
планировщиком.TaskScheduler.Default. Это
планировщик пула потоков. Он выполняет порученные задачи в
потоках из пула потоков. Время старта задачи при этом никак не
оговаривается. Второй пример -- это группа планировщиков, которые
предоставляет текущий синхронизационный контекст --
TaskScheduler.FromCurrentSynchronizationContext (например,
ASP.NET, WinForms или WPF). Соответственно задача, которая была
передана, например, планировщику WinForms, будет выполнена в главном
(UI) потоке.P.S. В 99% случаев достаточно вызывать Task.Run() и не связываться с TaskFactory.
Для начала, параллельно к TaskScheduler.Default есть ещё TaskScheduler.FromCurrentSynchronizationContext() (который в главном потоке WPF и WinForms создают scheduler, выполняющий задания в этом самом потоке). Кроме того, использовать TaskScheduler можно и в других местах, например, в Task.ContinueWith, ну и await тоже пользуется им под капотом.
Можно смотреть на TaskScheduler как на «прослойку» между отправкой таска на выполнение и самим выполнением. Но это собственно и есть смысл «планировки»: вы поставляете таск, а как и когда он будет запущен — вопрос, который решает планировщик (scheduler). То есть TaskScheduler — это не механизм внедрения вашего планировщика, это и есть планировщик!
Получается он не имеет какую-то внутреннюю логику по запуску задач отложено
Не получается. Ваш метод QueueTask — часть TaskScheduler'а, это и есть вызов внутренней логики по запуску задач!
Если я создам TaskScheduler через TaskScheduler.Default какая реализация будет у QueueTask
TaskScheduler.Default — планировщий на пуле потоков. Он просто выполнит ThreadPool.QueueUserWorkItem.
Из исходников .NET:
protected internal override void QueueTask(Task task)
{
if ((task.Options & TaskCreationOptions.LongRunning) != 0)
{
// Run LongRunning tasks on their own dedicated thread.
Thread thread = new Thread(s_longRunningThreadWork);
thread.IsBackground = true; // Keep this thread from blocking process shutdown
thread.Start(task);
}
else
{
// Normal handling for non-LongRunning tasks.
bool forceToGlobalQueue = ((task.Options & TaskCreationOptions.PreferFairness) != 0);
ThreadPool.UnsafeQueueCustomWorkItem(task, forceToGlobalQueue);
}
}
В примерах с QueueTask кроме отложенного запуска задачи делают добавление этой задачи в очередь... Зачем?
Это нужно спрашивать у авторов примера — скорее всего, в коде примера видно, откуда ещё производится доступ к очереди. ThreadPoolTaskScheduler, например, в QueueTask ничего не добавляет.
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости