-
Notifications
You must be signed in to change notification settings - Fork 858
feat(Async): RunSynchronouslyImmediate #19804
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
41f5f13
69e41a2
19e3482
cc7fe0b
173a0ed
f9e0383
d6ca6e0
013acc1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -896,6 +896,22 @@ module AsyncPrimitives = | |
| ccont = (fun cexn -> ctxt.PostWithTrampoline syncCtxt (fun () -> ctxt.ccont cexn)) | ||
| ) | ||
|
|
||
| [<DebuggerHidden>] | ||
| let StartWithContinuations cancellationToken (computation: Async<'T>) cont econt ccont = | ||
| let trampolineHolder = TrampolineHolder() | ||
|
|
||
| trampolineHolder.ExecuteWithTrampoline(fun () -> | ||
| let ctxt = | ||
| AsyncActivation.Create | ||
| cancellationToken | ||
| trampolineHolder | ||
| (cont >> fake) | ||
| (econt >> fake) | ||
| (ccont >> fake) | ||
|
|
||
| computation.Invoke ctxt) | ||
| |> unfake | ||
|
|
||
| [<Sealed>] | ||
| [<AutoSerializable(false)>] | ||
| type SuspendedAsync<'T>(ctxt: AsyncActivation<'T>) = | ||
|
|
@@ -1096,7 +1112,7 @@ module AsyncPrimitives = | |
|
|
||
| /// Run the asynchronous workflow and wait for its result. | ||
| [<DebuggerHidden>] | ||
| let QueueAsyncAndWaitForResultSynchronously (token: CancellationToken) computation timeout = | ||
| let QueueAsyncAndWaitForResultSynchronously computation (token: CancellationToken) timeout = | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can revert this, but trying to get arg order consistent across most involved functions |
||
| let token, innerCTS = | ||
| // If timeout is provided, we govern the async by our own CTS, to cancel | ||
| // when execution times out. Otherwise, the user-supplied token governs the async. | ||
|
|
@@ -1138,31 +1154,26 @@ module AsyncPrimitives = | |
| res.Commit() | ||
|
|
||
| [<DebuggerHidden>] | ||
| let RunImmediate (cancellationToken: CancellationToken) computation = | ||
| use resultCell = new ResultCell<AsyncResult<_>>() | ||
| let trampolineHolder = TrampolineHolder() | ||
|
|
||
| trampolineHolder.ExecuteWithTrampoline(fun () -> | ||
| let ctxt = | ||
| AsyncActivation.Create | ||
| cancellationToken | ||
| trampolineHolder | ||
| (fun res -> resultCell.RegisterResult(AsyncResult.Ok res, reuseThread = true)) | ||
| (fun edi -> resultCell.RegisterResult(AsyncResult.Error edi, reuseThread = true)) | ||
| (fun exn -> resultCell.RegisterResult(AsyncResult.Canceled exn, reuseThread = true)) | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. old behavior resulting in OperationCanceledException |
||
| let RunSynchronouslyImmediate<'T> computation (cancellationToken: CancellationToken) = | ||
| let tcs = TaskCompletionSource<'T>() | ||
|
|
||
| computation.Invoke ctxt) | ||
| |> unfake | ||
|
|
||
| let res = resultCell.TryWaitForResultSynchronously().Value | ||
| res.Commit() | ||
| StartWithContinuations | ||
| cancellationToken | ||
| computation | ||
| tcs.SetResult | ||
| (fun edi -> tcs.SetException edi.SourceException) | ||
| // NOTE In this case, cancellation will surface as a TaskCanceledException (with CT.None) from GetResult() | ||
| // (as opposed to the OperationCanceledException that RegisterResult cancellation ends up mapping to) | ||
| (fun _operationCanceledExn -> tcs.SetCanceled()) | ||
| // Synchronously block waiting for the result (i.e. even if continuations run on another thread, caller thread will be blocked) | ||
| tcs.Task.GetAwaiter().GetResult() // GetResult() unpacks the AggregateException that .Result would present | ||
|
|
||
| [<DebuggerHidden>] | ||
| let RunSynchronously cancellationToken (computation: Async<'T>) timeout = | ||
| // Reuse the current ThreadPool thread if possible. | ||
| let RunSynchronouslyBackgroundThreadPool (computation: Async<'T>) cancellationToken timeout = | ||
| // Run inline only where it's guaranteed to be safe | ||
| match SynchronizationContext.Current, Thread.CurrentThread.IsThreadPoolThread, timeout with | ||
| | null, true, None -> RunImmediate cancellationToken computation | ||
| | _ -> QueueAsyncAndWaitForResultSynchronously cancellationToken computation timeout | ||
| | null, true, None -> RunSynchronouslyImmediate computation cancellationToken // best stacktrace in case of exception | ||
|
Comment on lines
+1157
to
+1175
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @T-Gro this is the key implication of settling on a uniform simplified impl of IMO If we roll it back, we get messier stack traces and uglier code so I'm suggesting we take this inconsistency hit. |
||
| | _ -> QueueAsyncAndWaitForResultSynchronously computation cancellationToken timeout // less useful stack traces | ||
|
|
||
| [<DebuggerHidden>] | ||
| let Start cancellationToken (computation: Async<unit>) = | ||
|
|
@@ -1174,22 +1185,6 @@ module AsyncPrimitives = | |
| computation | ||
| |> unfake | ||
|
|
||
| [<DebuggerHidden>] | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. moved up as required by RunSynchronously note the whole PR could be made much shorter by having the Async layer call Async.FromContinuations However, as mentioned in other places, I believe its for the best that RunSynchronouslyImmediate and the immediate path of RunSychronously should have strong clear ties in the lower layer as this PR does |
||
| let StartWithContinuations cancellationToken (computation: Async<'T>) cont econt ccont = | ||
| let trampolineHolder = TrampolineHolder() | ||
|
|
||
| trampolineHolder.ExecuteWithTrampoline(fun () -> | ||
| let ctxt = | ||
| AsyncActivation.Create | ||
| cancellationToken | ||
| trampolineHolder | ||
| (cont >> fake) | ||
| (econt >> fake) | ||
| (ccont >> fake) | ||
|
|
||
| computation.Invoke ctxt) | ||
| |> unfake | ||
|
|
||
| [<DebuggerHidden>] | ||
| let StartAsTask cancellationToken (computation: Async<'T>) taskCreationOptions = | ||
| let taskCreationOptions = defaultArg taskCreationOptions TaskCreationOptions.None | ||
|
|
@@ -1511,7 +1506,13 @@ type Async = | |
| | Some token when not token.CanBeCanceled -> timeout, token | ||
| | Some token -> None, token | ||
|
|
||
| RunSynchronously cancellationToken computation timeout | ||
| RunSynchronouslyBackgroundThreadPool computation cancellationToken timeout | ||
|
|
||
| static member RunSynchronouslyImmediate(computation: Async<'T>, ?cancellationToken: CancellationToken) = | ||
| let cancellationToken = | ||
| defaultArg cancellationToken defaultCancellationTokenSource.Token | ||
|
|
||
| RunSynchronouslyImmediate computation cancellationToken | ||
|
|
||
| static member Start(computation, ?cancellationToken) = | ||
| let cancellationToken = | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved up as new RunSynchronouslyImmediate needs it (putting it there as the diffs look even more confusing if I put it as far down the file as possible)