There is no reasonable way to write an infinite loop, such as one that polls looking for work to do, using FSharpx.Task.
Repro steps
The simplest repro is a console application:
open FSharpx.Task
let whileLoop() =
task {
while true do
do! Task.FromResult(())
}
let main argv =
whileLoop().Wait()
0
Expected behavior
The application runs indefinitely, doing nothing, with stable memory usage.
Actual behavior
The application runs for a minute or two, doing nothing, but steadily growing in memory usage until throwing an OutOfMemoryException.
Known workarounds
As far as I know there is no clean functional way to chain tasks together that does not suffer from this problem. That is, implementing TaskBuilder.Bind using ContinueWith and Unwrap inevitably causes this. One known workaround is to use System.Runtime.CompilerServices.AsyncMethodBuilder to implement the loop (like the state machines that C#'s async/await construct compiles to).
I'm reporting this just as a heads-up after I realized it while trying to support constant-space tail recursion in my own TaskBuilder. My TaskBuilder is fine in imperative loops like while true because it uses an AsyncMethodBuilder, but its API is not 100% compatible with the one in FSharpx, so it's not a drop-in replacement. Its code is public domain though, so anybody who wishes to fix this issue in FSharpx is free to reference/copy it.
Related information
Operating system: Windows 7, Windows 10
Branch: master
.NET Runtime, CoreCLR or Mono Version: .NET framework 4.6.2
Description
There is no reasonable way to write an infinite loop, such as one that polls looking for work to do, using FSharpx.Task.
Repro steps
The simplest repro is a console application:
Expected behavior
The application runs indefinitely, doing nothing, with stable memory usage.
Actual behavior
The application runs for a minute or two, doing nothing, but steadily growing in memory usage until throwing an
OutOfMemoryException
.Known workarounds
As far as I know there is no clean functional way to chain tasks together that does not suffer from this problem. That is, implementing
TaskBuilder.Bind
usingContinueWith
andUnwrap
inevitably causes this. One known workaround is to useSystem.Runtime.CompilerServices.AsyncMethodBuilder
to implement the loop (like the state machines that C#'s async/await construct compiles to).I'm reporting this just as a heads-up after I realized it while trying to support constant-space tail recursion in my own TaskBuilder. My TaskBuilder is fine in imperative loops like
while true
because it uses anAsyncMethodBuilder
, but its API is not 100% compatible with the one in FSharpx, so it's not a drop-in replacement. Its code is public domain though, so anybody who wishes to fix this issue in FSharpx is free to reference/copy it.Related information