Replies: 3 comments 6 replies
-
The general problem with hot start task is that even before In effect, if we have a degenerated situation with a task that does not yield at all, like in the example above, it will stack overflow no matter what. There are ways to work around this, but it gets rather ugly quickly. |
Beta Was this translation helpful? Give feedback.
-
And there is already a built-in way to achieve any depth of recursion, tail-call or not, without stack overflow. Just make sure initial This actually runs fine: let rec t n = backgroundTask {
try
if n % 1000 = 0 then
printfn "in t %d" n
do! System.Threading.Tasks.Task.Yield() // This prevents stack overflow by deferring ReturnFrom to next state machine step.
if n > 0 then
return! t (n - 1)
else printfn "done!"
finally ()
}
t 1000_000 |> _.Wait() The real problem is that if this throws somewhere deep, stack unwind will take forever. |
Beta Was this translation helpful? Give feedback.
-
I gave it some more thought and came to a conclusion this makes no sense. The only thing to gain would be to prevent the allocation of intermediate |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I'd like to draft an idea of implementation that has a chance to actually work.
consider
This is currently
ReturnFrom
:ReturnFromFinal
should do something likeLet's call the first task that does
return!
and enters the loop "the runner".The runner would execute the tail call loop. It would await the
tailCallTarget
. IftailCallTarget
got updated to a next one - do another iteration, if not - finish and return its result.Now, the problem to solve is how to communicate between state machines. The task awaited as tail call target needs to know it is a tail call target. In case it executes
return!
itself, it needs to doupdateTailCallTarget
for the runner to see.One way to solve this is to keep that data in a static
AsyncLocal
. That way it would be available as a communication channel between the runner task and its subsequent tail call targets.Another is to use a
ConditionalWeakTable
to attach the needed data to task instances.Beta Was this translation helpful? Give feedback.
All reactions