I would like to run a function in a background thread, then consume the result with a timeout from an async context.
Here is my code:
open System.Threading.Tasks
let forever () =
while true do
()
123
async {
printfn "Computing..."
let! ct = Async.CancellationToken
let! c =
Task.Run(forever, ct)
|> Async.AwaitTask
|> fun t -> Async.StartChild(t, millisecondsTimeout = 1_000)
let! x = c
printfn $"%i{x}"
}
|> Async.RunSynchronously
I would expect this to raise an exception after 1 second, but it hangs forever.
How can I fix this?
This smells of https://xyproblem.info hence I'd suggest posting a followup that is more representative of your overall needs (i.e. to what degree are you mixing Task and Async in your real problem; are you trying to make a general helper, or just trying to understand things)
asyncexpressions check for cancellation of the ambient CT at wait points (i.e. alet!etc).taskexpressions (and Task stuff in general) has no such semanticsforevercannot be cancelled in any meaningful way as it is written asCancellationToken.IsCancellationTokenRequestedto trigger the end of the loopIf you'll allow some soapboxing, the high level conclusion of all this is:
taskstuff ANYWHERE, you should flow cancellation tokens to make yourself think and consider all the casesasync {, with brief call-outs to Task stuff as required, but always passing a CTtaskin the box now, we no longer need to pay the allocation and slight perf rax ofAsyncare very mistaken - you can't afford fortaskto leak into your code. If theasync {Builder ever gets rewritten to take advantage of the resumable state machine mechanisms thattaskuses, then the overhead drops more. Some of that future is already being explored in https://github.com/TheAngryByrd/IcedTasks etcYou have multiple style issues in your snippet which don't make it easy to five a succinct answer:
Async.StartAsTasketc. Highly recommend multiple reads of https://learn.microsoft.com/en-us/dotnet/fsharp/tutorials/asyncHelper for doing this inside a
taskexpr:It's consumed in the Propulsion project in various ways
An alternate approach (closer to what you're trying) is something like: (source)