Какой планировщик задач следует использовать для ContinueWith в ASP.NET Core

Я написал простой дебаунсер для использования с ASP.NET Core 5 (для обнаружения изменений в файлах конфигурации). Это будет использоваться в классе Startup. Это работает хорошо.

Однако я получаю предупреждение анализатора:

Не создавайте задачи без передачи TaskScheduler csharp(CA2008)

Код проблемы:

Task.Delay(TimeSpan.FromSeconds(2)).ContinueWith(
  task => someAction(),
  cancellationToken
);

Что из следующего я должен использовать, и как они отличаются?

Task.Delay(TimeSpan.FromSeconds(2)).ContinueWith(
  task => someAction(),
  cancellationToken,
  TaskContinuationOptions.None,
  TaskScheduler.FromCurrentSynchronizationContext()             // <---
);
Task.Delay(TimeSpan.FromSeconds(2)).ContinueWith(
  task => someAction(),
  cancellationToken,
  TaskContinuationOptions.None,
  TaskScheduler.Default                                          // <---
);

person lonix    schedule 04.03.2021    source источник
comment
ASP.NET Core не использует SynchronizationContext. Прочтите статью Стивена Клири   -  person Peter Csala    schedule 04.03.2021
comment
Вы должны использовать TaskScheduler.Default   -  person Matthew Watson    schedule 04.03.2021
comment
@MatthewWatson Спасибо, если вы добавите это в качестве ответа, я закрою :)   -  person lonix    schedule 04.03.2021
comment
@lonix зачем менять планировщик задач? Или использовать ContinueWith? Значение по умолчанию (возвращаемое TaskScheduler.Default) работает нормально. await Task.Delay(TimeSpan.FromSeconds(2)); тоже работает нормально   -  person Panagiotis Kanavos    schedule 04.03.2021
comment
@PanagiotisKanavos Я бы даже не подумал об этом, если бы не CA2008, поэтому я просто хочу использовать то, что является безопасным по умолчанию в ядре aspnet, к сожалению, я не знаю, что это такое. Я продолжаю читать, что это источник ошибок, если это не сделано должным образом, отсюда и мой вопрос.   -  person lonix    schedule 04.03.2021
comment
@lonix это правило жалуется на ContinueWith не Task.Delay. Почему бы вам не использовать await ? В ASP.NET Core нет SynchronizationContext, поэтому await не будет блокироваться.   -  person Panagiotis Kanavos    schedule 04.03.2021
comment
@PanagiotisKanavos Хотел бы я это сделать, но он вызывается из Startup.Configure(), который не является асинхронным.   -  person lonix    schedule 04.03.2021
comment
@lonix в этом случае у вас есть более серьезная ошибка - вызов асинхронного кода в методе синхронизации. В какой-то момент вам придется заблокировать и вот могут возникнуть проблемы. Я мог бы даже сказать, что Configure не место для включения логических и асинхронных операций. Если вы хотите включить параметры конфигурации из удаленного источника, создайте отдельный поставщик конфигурации и реализуйте его асинхронные операции. Работа Configure состоит в том, чтобы подключать источники, а не действовать как источник   -  person Panagiotis Kanavos    schedule 04.03.2021
comment
Не используйте ContinueWith для добавления продолжений, используйте await для добавления продолжений к методам. Это значительно упрощает написание правильного кода.   -  person Servy    schedule 04.03.2021
comment
@PanagiotisKanavos Я согласен с вами, но, к сожалению, то, что я сделал, кажется распространенным способом - при обнаружении изменений в файлах appsettings.json мы должны отменить несколько обнаружений изменений при записи файла (это сбой фреймворка), и это указывается при запуске приложения в Startup.cs   -  person lonix    schedule 04.03.2021
comment
@lonix обычный способ - использовать поставщика конфигурации файла и позволить ону обрабатывать изменения. Не должно быть никаких причин для обработки множественных изменений, если только appsettings не используется необычным образом - переписывая его, например, для изменения отдельных записей или, что еще хуже, когда само приложение изменяет файл. Если вы хотите изменить настройки во время выполнения, используйте другой источник, например источник в памяти.   -  person Panagiotis Kanavos    schedule 04.03.2021
comment
@PanagiotisKanavos На самом деле это хорошо известная проблема, возникшая много лет назад. И то, как я это сделал, кажется нормой как в репо, так и здесь, на SO. Но я приму к сведению то, что вы сказали, спасибо.   -  person lonix    schedule 04.03.2021
comment
@PanagiotisKanavos Я учел ваши комментарии и остановился на размещенном сервисе, который является асинхронным, спасибо, что указали мне правильно дорожка. Я ответил на вопрос, как он есть в любом случае.   -  person lonix    schedule 05.03.2021
comment
Настоящая проблема заключается не в том, что описывает эта проблема, поэтому она была закрыта. Когда вы копируете файл, Windows выдает одно уведомление о создании файла и одно или несколько об изменении файла. Событие file closed отсутствует, поэтому невозможно узнать, когда файл копируется. Если приложение умное и выделяет все необходимое пространство перед записью каких-либо изменений в файл, вы можете получить только 1 событие изменения файла, даже для больших файлов.   -  person Panagiotis Kanavos    schedule 05.03.2021
comment
@lonix на самом деле, изменяющее приложение может все еще записывать в цель, когда оно получает уведомление об изменении, что приводит к исключения доступа к файлу при попытке прочитать измененный файл. Единственное решение — отклонять события изменения и реагировать на них только после того, как пройдет достаточно времени простоя. Такие библиотеки, как ReactiveX, значительно упрощают эту задачу. Без Rx каждое событие могло бы сбрасывать таймер, обработчик которого позаботится об уведомлениях.   -  person Panagiotis Kanavos    schedule 05.03.2021
comment
@lonix, поэтому OneDrive, DropBox и GDrive не начинают синхронизацию сразу, когда вы копируете файлы в их папку.   -  person Panagiotis Kanavos    schedule 05.03.2021
comment
@PanagiotisKanavos Да, это именно то, что я сделал, подход debouncer. Лол, есть что-то, чего ты не знаешь о дотнете??? Наслаждайся своими выходными! :)   -  person lonix    schedule 05.03.2021
comment
@lonix Я создал инструмент синхронизации файлов, похожий на Dropbox, еще в 2010 году, который использовался для синхронизации больших файлов VHD. Мне потребовалось некоторое время, чтобы понять, почему я получаю так мало уведомлений об изменениях, когда кто-то копирует виртуальный жесткий диск в папку синхронизации. Проводник достаточно умен, чтобы предварительно выделить весь файл. После этого события изменения возникают только тогда, когда буфер копирования сбрасывается на диск. Windows динамически изменяет размеры буфера, поэтому то, что я наблюдал при копировании большого количества небольших файлов, отличалось от того, что наблюдал клиент при копировании эпизода «Игры престолов» размером 4 ГБ в тестовых целях.   -  person Panagiotis Kanavos    schedule 05.03.2021
comment
@PanagiotisKanavos Ха, да, всегда используйте данные реального мира для целей тестирования. Я думаю, что в linux/macos вместо этого фреймворк полагается на функцию inotify (которая вызывает уведомления после завершения записи файла), хотя я могу ошибаться, поскольку не тестировал ее с реальными данными. Устранение дребезга в 2-3 секунды, кажется, работает для меня на Linux в производстве.   -  person lonix    schedule 05.03.2021


Ответы (1)


Согласно этому, ASP.NET Core не имеет SynchronizationContext.

Итак, согласно приведенному выше комментарию @MatthewWatson, можно использовать TaskScheduler.Default.

person lonix    schedule 05.03.2021