Учитывая программу fsharp, например:
[<EntryPoint>]
let main argv =
use cancel = new CancellationTokenSource ()
Console.CancelKeyPress.Add (fun _ -> cancel.Cancel ())
let sleep = async {
try
do! Async.Sleep 20_000
finally
printfn "Finished"
}
Async.RunSynchronously (sleep, cancellationToken = cancel.Token)
printfn "done"
0
когда я нажимаю Ctrl+C через несколько секунд, что должно произойти?
Я ожидал, что он напечатает «завершено», затем «готово», а затем выйдет. Вместо этого он печатает «завершено», а затем зависает.
(Если я взломаю отладчик, я увижу, что основной поток все еще находится на FSharp.Core.dll!Microsoft.FSharp.Control.FSharpAsync.RunSynchronously<Microsoft.FSharp.Core.Unit>
.)
Что я должен сделать вместо этого, чтобы получить поведение, которое я ищу?
У меня не висит. Вместо этого я вижу «Готово» (потому что блок finally
запускается, когда сон прерывается), а затем процесс завершается (потому что это то, что Ctrl-C делает по умолчанию).
Чтобы получить желаемое поведение, мне пришлось сделать это вместо этого:
open System
open System.Threading
[<EntryPoint>]
let main argv =
use cancel = new CancellationTokenSource ()
Console.CancelKeyPress.Add (fun args ->
cancel.Cancel ()
args.Cancel <- true) // prevent Ctrl-C from terminating the process
let sleep = async {
do! Async.Sleep 20_000
}
try
Async.RunSynchronously (sleep, cancellationToken = cancel.Token)
with :? OperationCanceledException ->
printfn "Finished"
printfn "done"
0
Когда я запускаю это из Visual Studio, а затем нажимаю Ctrl-C, я вижу:
Finished
done
C:\Users\brian\source\repos\FSharpConsole\FSharpConsole\bin\Debug\net7.0\FSharpConsole.exe (process 35072) exited with code 0.
Press any key to close this window . . .
Спасибо! Добавление
args.Cancel <- true
приводит к возникновению OperationCanceledException, после чего процесс завершается. Без него я тоже вижу "законченное", но ничего больше. (Процесс не завершается, в выводе нет необработанных исключений.)