Я бы не сказал, что это ошибка - она вытекает из способа обработки отмены в асинхронных рабочих процессах F # в целом. Как правило, F # предполагает, что примитивные операции, которые вы вызываете с использованием let!
или do!
, не поддерживают отмену (я полагаю, что в .NET нет стандартного механизма для этого), поэтому F # вставляет проверки отмены до и после вызова, сделанного с использованием let!
.
Так что вызов let! res = foo()
на самом деле больше похож на следующий (хотя проверки скрыты в реализации библиотеки async
):
token.ThrowIfCancellationRequested()
let! res = foo()
token.ThrowIfCancellationRequested()
Конечно, рабочий процесс, возвращаемый foo()
, может лучше обрабатывать отмену - обычно, если он реализован с использованием блока async { .. }
, он будет содержать больше проверок вокруг каждого let!
. Однако в общем случае (если какая-либо операция не реализована более умным способом), отмена будет выполнена после завершения следующего вызова let!
.
Ваше альтернативное определение Sleep
выглядит для меня довольно неплохо - оно поддерживает отмену лучше, чем то, что доступно в библиотеке F #, и если вам нужно немедленное отмену, то замена F 101 Async.Sleep
на SleepEx
- единственный способ идти. Однако, вероятно, все еще будут некоторые операции, которые не поддерживают немедленную отмену, поэтому вы можете столкнуться с проблемами в другом месте (если вам нужно такое поведение везде).
PS: Я думаю, что ваша функция SleepEx
может быть очень полезна для других. Если бы вы могли поделиться им на веб-сайте F # Snippets , это было бы здорово!