feat(Async): RunSynchronouslyImmediate#19804
Conversation
❗ Release notes required
|
181ce94 to
41f5f13
Compare
d6a0470 to
69e41a2
Compare
There was a problem hiding this comment.
Pull request overview
Adds Async.RunSynchronouslyImmediate to FSharp.Core to allow running an Async<'T> synchronously while always executing the initial step on the calling thread (aimed at improved diagnostics/stack traces in FSI/tests), with accompanying API surface updates, documentation, unit tests, and release notes.
Changes:
- Add public API
Async.RunSynchronouslyImmediateand wire it through Async primitives. - Add unit tests characterizing basic behavior and key differences vs
Async.RunSynchronously. - Update FSharp.Core surface area baselines and release notes; extend XML docs for
RunSynchronously/RunSynchronouslyImmediate.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModule.fs | Adds unit tests for RunSynchronouslyImmediate and contrasts with RunSynchronously. |
| tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl | Records new public surface area entry for RunSynchronouslyImmediate. |
| tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl | Records new public surface area entry for RunSynchronouslyImmediate. |
| tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl | Records new public surface area entry for RunSynchronouslyImmediate. |
| tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl | Records new public surface area entry for RunSynchronouslyImmediate. |
| src/FSharp.Core/async.fsi | Adds XML docs for the new API and revises RunSynchronously docs to reference it. |
| src/FSharp.Core/async.fs | Implements the new API by exposing an “immediate” synchronous runner and refactoring RunSynchronously internals. |
| docs/release-notes/.FSharp.Core/11.0.100.md | Adds release note entry for Async.RunSynchronouslyImmediate. |
Comments suppressed due to low confidence (1)
tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModule.fs:527
- This test uses a raw Thread but doesn’t capture exceptions from the thread body. Any unexpected exception inside the thread (including from Async.RunSynchronously) will be unhandled and may crash the test process rather than reporting a normal xUnit failure. Capture exceptions in the thread and rethrow/assert after Join.
let t = Thread(fun () ->
callerThreadId <- Thread.CurrentThread.ManagedThreadId
async { runSyncThreadId <- Thread.CurrentThread.ManagedThreadId }
|> Async.RunSynchronously
async { immThreadId <- Thread.CurrentThread.ManagedThreadId }
|> Async.RunSynchronouslyImmediate)
| /// <summary><p>Runs the asynchronous computation, starting and blocking on the | ||
| /// calling thread regardless of <see cref="P:System.Threading.SynchronizationContext.Current"/> being non- | ||
| /// <c>null</c> or <see cref="P:System.Threading.Thread.IsThreadPoolThread"/> being <c>false</c>.</p> | ||
| /// <p>Any exception raised by the computation is propagated to the caller, with a stack trace bearing | ||
| /// caller frames for exceptions raised before the first asynchronous suspension.</p> | ||
| /// <p>Warning: may cause deadlock if called on a UI thread.</p> | ||
| /// </summary> | ||
| /// | ||
| /// The timeout parameter is given in milliseconds. A value of -1 is equivalent to | ||
| /// <see cref="F:System.Threading.Timeout.Infinite"/>. | ||
| /// <remarks> | ||
| /// <p>Warning: this method hard-blocks the calling thread for the duration of the computation, | ||
| /// including threads that have a non-<c>null</c> | ||
| /// <see cref="P:System.Threading.SynchronizationContext.Current"/> such as UI threads. Calling it | ||
| /// from a UI thread will make the UI unresponsive and risks deadlock if any continuation in the | ||
| /// computation needs to be dispatched back to that context. | ||
| /// </p> |
There was a problem hiding this comment.
Summary and remarks feel very much like.
Maybe summary = launches on the calling thread and what it is good for
remarks - the exact conditions and risks
?
| /// </code> | ||
| /// Prints "A", "B" immediately, then "C", "D" in 1 second. result is set to 17. | ||
| /// Prints <c>"A"</c>, <c>"B"</c> immediately (on the calling thread), | ||
| /// then (from a continuation thread), after about one second, <c>"C"</c>, |
There was a problem hiding this comment.
Isn't the example commentary ((from a continuation thread)) swapped between the two versions?
Implements
RunSynchronouslyImmediateper fsharp/fslang-suggestions#1042See also fsharp/fslang-suggestions#1467
NOTE the tests (and especially the comments within them) are mainly generated. Similarly the xmldoc updates are a best effort mix of generated content combined with me attempting to increase chances that an intellisense reader will come to the right conclusions in terms of tradeoff between potential deadlock vs better stacktraces. As such, please feel free to relentlessly criticize and/or rewrite to your hearts content.
Checklist
Async.RSvsAsync.RSIRunSynchronously)