Я ищу объяснение того, почему .NET CancellationToken
struct была введена в дополнение к CancellationTokenSource
классу. Я понимаю, как следует использовать API, но хочу также понять, почему он так устроен.
Т.е. почему у нас:
var cts = new CancellationTokenSource();
SomeCancellableOperation(cts.Token);
...
public void SomeCancellableOperation(CancellationToken token) {
...
token.ThrowIfCancellationRequested();
...
}
вместо прямой передачи, CancellationTokenSource
например:
var cts = new CancellationTokenSource();
SomeCancellableOperation(cts);
...
public void SomeCancellableOperation(CancellationTokenSource cts) {
...
cts.ThrowIfCancellationRequested();
...
}
Это оптимизация производительности, основанная на том факте, что проверки состояния отмены происходят чаще, чем передача токена?
Чтобы CancellationTokenSource
можно было отслеживать и обновлять CancellationTokens
, и для каждого токена проверка отмены является доступом к локальному полю?
Учитывая, что в обоих случаях достаточно volatile bool без блокировки, я все еще не понимаю, почему это будет быстрее.
Спасибо!
У меня был точный вопрос, и я хотел понять смысл этого дизайна.
В принятом ответе было правильное обоснование. Вот подтверждение от команды, которая разработала эту функцию (выделено мной):
Ссылка: .NET 4 Cancellation Framework
На мой взгляд,
CancellationToken
крайне критично то, что можно только наблюдать за состоянием, а не изменять его. Вы можете раздать жетон как конфету и никогда не беспокоиться, что кто-то другой, кроме вас, отменит его. Он защищает вас от враждебного стороннего кода. Да, шансы невелики, но лично мне эта гарантия нравится.Я также считаю, что это делает API чище, позволяет избежать случайной ошибки и способствует лучшему дизайну компонентов.
Давайте посмотрим на общедоступный API для обоих этих классов.
Если бы вы скомбинировали их при написании LongRunningFunction, я увижу такие методы, как несколько перегрузок «Отмена», которые мне не следует использовать. Лично мне тоже не нравится метод Dispose.
Я думаю, что нынешний дизайн класса следует философии «ямы успеха», он помогает разработчикам создавать лучшие компоненты, которые могут обрабатывать
Task
отмену, а затем объединять их различными способами для создания сложных рабочих процессов.Позвольте мне задать вам вопрос, вы задавались вопросом, для чего нужен токен.Регистрация? Для меня это не имело смысла. А потом я прочитал « Отмена в управляемых потоках», и все стало предельно ясно.
Я считаю, что дизайн системы отмены в TPL абсолютно на высшем уровне.
источник
CancellationTokenSource
самом деле может инициировать запрос отмены для связанного с ним токена (токен не может сделать это сам по себе): CancellationToken имеет этот внутренний конструктор:internal CancellationToken(CancellationTokenSource source) { this.m_source = source; }
и это свойство:public bool IsCancellationRequested { get { return this.m_source != null && this.m_source.IsCancellationRequested; } }
CancellationTokenSource использует внутренний конструктор, поэтому токен имеет ссылку на источник (m_source)Они разделены не по техническим, а по смысловым причинам. Если вы посмотрите на реализацию
CancellationToken
под ILSpy, вы обнаружите, что это просто оболочкаCancellationTokenSource
(и, следовательно, не отличается по производительности от передачи ссылки).Они обеспечивают такое разделение функциональности, чтобы сделать вещи более предсказуемыми: когда вы передаете метод a
CancellationToken
, вы знаете, что по-прежнему единственный, кто может его отменить. Конечно, метод все еще может генерировать aTaskCancelledException
, ноCancellationToken
сам по себе - и любые другие методы, ссылающиеся на тот же токен - останутся безопасными.источник
CancellationTokenSource
. Можно подумать, что можно просто сказать «не делай этого», но люди (включая меня!) Иногда делают это, чтобы получить доступ к некоторым скрытым функциям, и это произойдет. По крайней мере, это моя текущая теория.Это
CancellationToken
структура, поэтому может существовать много копий из-за передачи ее методам.В
CancellationTokenSource
устанавливает состояние всех копий токена при вызовеCancel
на источник. См. Эту страницу MSDNПричина дизайна может быть просто вопросом разделения задач и скорости структуры.
источник
Это
CancellationTokenSource
"вещь", которая вызывает отмену по любой причине. Ему нужен способ «отправить» эту отмену всемCancellationToken
выданным им. Вот как, например, ASP.NET может отменять операции, когда запрос прерывается. Каждый запрос имеет объект,CancellationTokenSource
который перенаправляет отмену всем выпущенным им токенам.Это отлично подходит для модульного тестирования BTW - создайте свой собственный источник токена отмены, получите токен, вызовите
Cancel
источник и передайте токен в свой код, который должен обрабатывать отмену.источник