diff --git a/src/FSharp.Core/async.fs b/src/FSharp.Core/async.fs
index e907040c94c..ce9b05445b8 100644
--- a/src/FSharp.Core/async.fs
+++ b/src/FSharp.Core/async.fs
@@ -1501,6 +1501,10 @@ type Async =
computation.Invoke newCtxt)
+ static member RunImmediate(computation: Async<'T>, ?cancellationToken: CancellationToken) =
+ let cancellationToken = defaultArg cancellationToken Async.DefaultCancellationToken
+ AsyncPrimitives.RunImmediate cancellationToken computation
+
static member RunSynchronously(computation: Async<'T>, ?timeout, ?cancellationToken: CancellationToken) =
let timeout, cancellationToken =
match cancellationToken with
diff --git a/src/FSharp.Core/async.fsi b/src/FSharp.Core/async.fsi
index 3aa0403bb19..c1dc9bd953c 100644
--- a/src/FSharp.Core/async.fsi
+++ b/src/FSharp.Core/async.fsi
@@ -13,25 +13,25 @@ namespace Microsoft.FSharp.Control
///
/// An asynchronous computation, which, when run, will eventually produce a value of type T, or else raises an exception.
- ///
+ ///
///
///
/// This type has no members. Asynchronous computations are normally specified either by using an async expression
/// or the static methods in the type.
///
/// See also F# Language Guide - Async Workflows.
- ///
+ ///
///
///
/// Library functionality for asynchronous programming, events and agents. See also
- /// Asynchronous Programming,
+ /// Asynchronous Programming,
/// Events and
/// Lazy Expressions in the
/// F# Language Guide.
///
///
/// Async Programming
-
+
[]
type Async<'T>
@@ -47,6 +47,42 @@ namespace Microsoft.FSharp.Control
[]
type Async =
+ /// Runs the asynchronous computation and await its result.
+ ///
+ /// If an exception occurs in the asynchronous computation then an exception is re-raised by this
+ /// function.
+ ///
+ /// If no cancellation token is provided then the default cancellation token is used.
+ ///
+ /// The computation always starts on current thread.
+ ///
+ ///
+ ///
+ /// The computation to run.
+ /// The cancellation token to be associated with the computation.
+ /// If one is not supplied, the default cancellation token is used.
+ ///
+ /// The result of the computation.
+ ///
+ /// Starting Async Computations
+ ///
+ ///
+ ///
+ /// printfn "A"
+ ///
+ /// let result = async {
+ /// printfn "B"
+ /// do! Async.Sleep(1000)
+ /// printfn "C"
+ /// 17
+ /// } |> Async.RunImmediate
+ ///
+ /// printfn "D"
+ ///
+ /// Prints "A", "B" immediately, then "C", "D" in 1 second. result is set to 17.
+ ///
+ static member RunImmediate : computation: Async<'T> * ?cancellationToken: CancellationToken -> 'T
+
/// Runs the asynchronous computation and await its result.
///
/// If an exception occurs in the asynchronous computation then an exception is re-raised by this
@@ -90,7 +126,7 @@ namespace Microsoft.FSharp.Control
/// Prints "A", "B" immediately, then "C", "D" in 1 second. result is set to 17.
///
static member RunSynchronously : computation:Async<'T> * ?timeout : int * ?cancellationToken:CancellationToken-> 'T
-
+
/// Starts the asynchronous computation in the thread pool. Do not await its result.
///
/// If no cancellation token is provided then the default cancellation token is used.
@@ -170,7 +206,7 @@ namespace Microsoft.FSharp.Control
/// match DateTime.Today with
/// | dt when dt.DayOfWeek = DayOfWeek.Monday -> failwith "Not compatible with Mondays"
/// | dt -> dt
- ///
+ ///
/// async { return someRiskyBusiness() }
/// |> Async.Catch
/// |> Async.RunSynchronously
@@ -183,7 +219,7 @@ namespace Microsoft.FSharp.Control
static member Catch : computation:Async<'T> -> Async>
/// Creates an asynchronous computation that executes computation.
- /// If this computation is cancelled before it completes then the computation generated by
+ /// If this computation is cancelled before it completes then the computation generated by
/// running compensation is executed.
///
/// The input asynchronous computation.
@@ -218,11 +254,11 @@ namespace Microsoft.FSharp.Control
/// Generates a scoped, cooperative cancellation handler for use within an asynchronous workflow.
///
/// For example,
- /// async { use! holder = Async.OnCancel interruption ... }
- /// generates an asynchronous computation where, if a cancellation happens any time during
- /// the execution of the asynchronous computation in the scope of holder, then action
- /// interruption is executed on the thread that is performing the cancellation. This can
- /// be used to arrange for a computation to be asynchronously notified that a cancellation
+ /// async { use! holder = Async.OnCancel interruption ... }
+ /// generates an asynchronous computation where, if a cancellation happens any time during
+ /// the execution of the asynchronous computation in the scope of holder, then action
+ /// interruption is executed on the thread that is performing the cancellation. This can
+ /// be used to arrange for a computation to be asynchronously notified that a cancellation
/// has occurred, e.g. by setting a flag, or deregistering a pending I/O action.
///
/// The function that is executed on the thread performing the
@@ -252,11 +288,11 @@ namespace Microsoft.FSharp.Control
/// and then print "Computation Cancelled: 7", "Computation Cancelled: 11" and "Tasks Finished" in any order.
///
static member OnCancel : interruption: (unit -> unit) -> Async
-
- /// Creates an asynchronous computation that returns the CancellationToken governing the execution
+
+ /// Creates an asynchronous computation that returns the CancellationToken governing the execution
/// of the computation.
///
- /// In async { let! token = Async.CancellationToken ...} token can be used to initiate other
+ /// In async { let! token = Async.CancellationToken ...} token can be used to initiate other
/// asynchronous operations that will cancel cooperatively with this workflow.
///
/// An asynchronous computation capable of retrieving the CancellationToken from a computation
@@ -267,9 +303,9 @@ namespace Microsoft.FSharp.Control
///
static member CancellationToken : Async
- /// Raises the cancellation condition for the most recent set of asynchronous computations started
- /// without any specific CancellationToken. Replaces the global CancellationTokenSource with a new
- /// global token source for any asynchronous computations created after this point without any
+ /// Raises the cancellation condition for the most recent set of asynchronous computations started
+ /// without any specific CancellationToken. Replaces the global CancellationTokenSource with a new
+ /// global token source for any asynchronous computations created after this point without any
/// specific CancellationToken.
///
/// Cancellation and Exceptions
@@ -299,7 +335,7 @@ namespace Microsoft.FSharp.Control
/// This will print "2" 2 seconds from start, "3" 3 seconds from start, "5" 5 seconds from start, cease computation and
/// then print "Tasks Not Finished: One or more errors occurred. (A task was canceled.)".
///
- static member CancelDefaultToken : unit -> unit
+ static member CancelDefaultToken : unit -> unit
/// Gets the default cancellation token for executing asynchronous computations.
///
@@ -330,22 +366,22 @@ namespace Microsoft.FSharp.Control
//---------- Parallelism
- /// Starts a child computation within an asynchronous workflow.
+ /// Starts a child computation within an asynchronous workflow.
/// This allows multiple asynchronous computations to be executed simultaneously.
///
- /// This method should normally be used as the immediate
+ /// This method should normally be used as the immediate
/// right-hand-side of a let! binding in an F# asynchronous workflow, that is,
///
/// async { ...
- /// let! completor1 = childComputation1 |> Async.StartChild
- /// let! completor2 = childComputation2 |> Async.StartChild
- /// ...
- /// let! result1 = completor1
- /// let! result2 = completor2
+ /// let! completor1 = childComputation1 |> Async.StartChild
+ /// let! completor2 = childComputation2 |> Async.StartChild
+ /// ...
+ /// let! result1 = completor1
+ /// let! result2 = completor2
/// ... }
///
///
- /// When used in this way, each use of StartChild starts an instance of childComputation
+ /// When used in this way, each use of StartChild starts an instance of childComputation
/// and returns a completor object representing a computation to wait for the completion of the operation.
/// When executed, the completor awaits the completion of childComputation.
///
@@ -386,14 +422,14 @@ namespace Microsoft.FSharp.Control
/// Will throw a System.TimeoutException if called with a timeout less than 2000, otherwise will print "Result: 3".
///
static member StartChild : computation:Async<'T> * ?millisecondsTimeout : int -> Async>
-
- /// Creates an asynchronous computation that executes all the given asynchronous computations,
+
+ /// Creates an asynchronous computation that executes all the given asynchronous computations,
/// initially queueing each as work items and using a fork/join pattern.
///
/// If all child computations succeed, an array of results is passed to the success continuation.
///
- /// If any child computation raises an exception, then the overall computation will trigger an
- /// exception, and cancel the others.
+ /// If any child computation raises an exception, then the overall computation will trigger an
+ /// exception, and cancel the others.
///
/// The overall computation will respond to cancellation while executing the child computations.
/// If cancelled, the computation will cancel any remaining child computations but will still wait
@@ -515,7 +551,7 @@ namespace Microsoft.FSharp.Control
/// |> Async.StartAsTask
///
/// t.Wait()
- /// printfn $"%A{t.Result}"
+ /// printfn $"%A{t.Result}"
///
/// This will print "3", "5", "7", "11" with ~1-2 seconds between them except for pauses where even numbers would be and then
/// prints [| false; true; true; true; false; true |].
@@ -523,14 +559,14 @@ namespace Microsoft.FSharp.Control
static member Sequential : computations:seq> -> Async<'T[]>
///
- /// Creates an asynchronous computation that executes all given asynchronous computations in parallel,
+ /// Creates an asynchronous computation that executes all given asynchronous computations in parallel,
/// returning the result of the first succeeding computation (one whose result is 'Some x').
/// If all child computations complete with None, the parent computation also returns None.
///
///
///
- /// If any child computation raises an exception, then the overall computation will trigger an
- /// exception, and cancel the others.
+ /// If any child computation raises an exception, then the overall computation will trigger an
+ /// exception, and cancel the others.
///
/// The overall computation will respond to cancellation while executing the child computations.
/// If cancelled, the computation will cancel any remaining child computations but will still wait
@@ -594,7 +630,7 @@ namespace Microsoft.FSharp.Control
static member Choice : computations:seq> -> Async<'T option>
//---------- Thread Control
-
+
/// Creates an asynchronous computation that creates a new thread and runs
/// its continuation in that thread.
///
@@ -611,8 +647,8 @@ namespace Microsoft.FSharp.Control
///
/// This will run someLongRunningComputation() without blocking the threads in the threadpool.
///
- static member SwitchToNewThread : unit -> Async
-
+ static member SwitchToNewThread : unit -> Async
+
/// Creates an asynchronous computation that queues a work item that runs
/// its continuation.
///
@@ -634,10 +670,10 @@ namespace Microsoft.FSharp.Control
/// This will run someLongRunningComputation() without blocking the threads in the threadpool, and then switch to the
/// threadpool for shorter computations.
///
- static member SwitchToThreadPool : unit -> Async
+ static member SwitchToThreadPool : unit -> Async
/// Creates an asynchronous computation that runs
- /// its continuation using syncContext.Post. If syncContext is null
+ /// its continuation using syncContext.Post. If syncContext is null
/// then the asynchronous computation is equivalent to SwitchToThreadPool().
///
/// The synchronization context to accept the posted computation.
@@ -647,10 +683,10 @@ namespace Microsoft.FSharp.Control
/// Threads and Contexts
///
///
- static member SwitchToContext : syncContext:System.Threading.SynchronizationContext -> Async
+ static member SwitchToContext : syncContext:System.Threading.SynchronizationContext -> Async
/// Creates an asynchronous computation that captures the current
- /// success, exception and cancellation continuations. The callback must
+ /// success, exception and cancellation continuations. The callback must
/// eventually call exactly one of the given continuations.
///
/// The function that accepts the current success, exception, and cancellation
@@ -666,7 +702,7 @@ namespace Microsoft.FSharp.Control
/// match DateTime.Today with
/// | dt when dt.DayOfWeek = DayOfWeek.Monday -> failwith "Not compatible with Mondays"
/// | dt -> dt
- ///
+ ///
/// let computation =
/// (fun (successCont, exceptionCont, cancellationCont) ->
/// try
@@ -688,12 +724,12 @@ namespace Microsoft.FSharp.Control
///
static member FromContinuations : callback:(('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T>
- /// Creates an asynchronous computation that waits for a single invocation of a CLI
- /// event by adding a handler to the event. Once the computation completes or is
+ /// Creates an asynchronous computation that waits for a single invocation of a CLI
+ /// event by adding a handler to the event. Once the computation completes or is
/// cancelled, the handler is removed from the event.
///
- /// The computation will respond to cancellation while waiting for the event. If a
- /// cancellation occurs, and cancelAction is specified, then it is executed, and
+ /// The computation will respond to cancellation while waiting for the event. If a
+ /// cancellation occurs, and cancelAction is specified, then it is executed, and
/// the computation continues to wait for the event.
///
/// If cancelAction is not specified, then cancellation causes the computation
@@ -708,7 +744,7 @@ namespace Microsoft.FSharp.Control
/// Awaiting Results
///
///
- static member AwaitEvent: event:IEvent<'Del,'T> * ?cancelAction : (unit -> unit) -> Async<'T> when 'Del : delegate<'T,unit> and 'Del :> System.Delegate
+ static member AwaitEvent: event:IEvent<'Del,'T> * ?cancelAction : (unit -> unit) -> Async<'T> when 'Del : delegate<'T,unit> and 'Del :> System.Delegate
/// Creates an asynchronous computation that will wait on the given WaitHandle.
///
@@ -839,13 +875,13 @@ namespace Microsoft.FSharp.Control
static member Sleep: dueTime:TimeSpan -> Async
///
- /// Creates an asynchronous computation in terms of a Begin/End pair of actions in
+ /// Creates an asynchronous computation in terms of a Begin/End pair of actions in
/// the style used in CLI APIs.
///
///
///
/// The computation will respond to cancellation while waiting for the completion
- /// of the operation. If a cancellation occurs, and cancelAction is specified, then it is
+ /// of the operation. If a cancellation occurs, and cancelAction is specified, then it is
/// executed, and the computation continues to wait for the completion of the operation.
///
/// If cancelAction is not specified, then cancellation causes the computation
@@ -863,12 +899,12 @@ namespace Microsoft.FSharp.Control
static member FromBeginEnd : beginAction:(System.AsyncCallback * obj -> System.IAsyncResult) * endAction:(System.IAsyncResult -> 'T) * ?cancelAction : (unit -> unit) -> Async<'T>
///
- /// Creates an asynchronous computation in terms of a Begin/End pair of actions in
+ /// Creates an asynchronous computation in terms of a Begin/End pair of actions in
/// the style used in .NET 2.0 APIs.
///
///
/// The computation will respond to cancellation while waiting for the completion
- /// of the operation. If a cancellation occurs, and cancelAction is specified, then it is
+ /// of the operation. If a cancellation occurs, and cancelAction is specified, then it is
/// executed, and the computation continues to wait for the completion of the operation.
///
/// If cancelAction is not specified, then cancellation causes the computation
@@ -888,11 +924,11 @@ namespace Microsoft.FSharp.Control
static member FromBeginEnd : arg:'Arg1 * beginAction:('Arg1 * System.AsyncCallback * obj -> System.IAsyncResult) * endAction:(System.IAsyncResult -> 'T) * ?cancelAction : (unit -> unit) -> Async<'T>
///
- /// Creates an asynchronous computation in terms of a Begin/End pair of actions in
+ /// Creates an asynchronous computation in terms of a Begin/End pair of actions in
/// the style used in .NET 2.0 APIs.
///
/// The computation will respond to cancellation while waiting for the completion
- /// of the operation. If a cancellation occurs, and cancelAction is specified, then it is
+ /// of the operation. If a cancellation occurs, and cancelAction is specified, then it is
/// executed, and the computation continues to wait for the completion of the operation.
///
/// If cancelAction is not specified, then cancellation causes the computation
@@ -911,11 +947,11 @@ namespace Microsoft.FSharp.Control
///
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * beginAction:('Arg1 * 'Arg2 * System.AsyncCallback * obj -> System.IAsyncResult) * endAction:(System.IAsyncResult -> 'T) * ?cancelAction : (unit -> unit) -> Async<'T>
- /// Creates an asynchronous computation in terms of a Begin/End pair of actions in
+ /// Creates an asynchronous computation in terms of a Begin/End pair of actions in
/// the style used in .NET 2.0 APIs.
///
/// The computation will respond to cancellation while waiting for the completion
- /// of the operation. If a cancellation occurs, and cancelAction is specified, then it is
+ /// of the operation. If a cancellation occurs, and cancelAction is specified, then it is
/// executed, and the computation continues to wait for the completion of the operation.
///
/// If cancelAction is not specified, then cancellation causes the computation
@@ -935,7 +971,7 @@ namespace Microsoft.FSharp.Control
///
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * arg3:'Arg3 * beginAction:('Arg1 * 'Arg2 * 'Arg3 * System.AsyncCallback * obj -> System.IAsyncResult) * endAction:(System.IAsyncResult -> 'T) * ?cancelAction : (unit -> unit) -> Async<'T>
- /// Creates three functions that can be used to implement the .NET 1.0 Asynchronous
+ /// Creates three functions that can be used to implement the .NET 1.0 Asynchronous
/// Programming Model (APM) for a given asynchronous computation.
///
/// A function generating the asynchronous computation to split into the traditional
@@ -946,15 +982,15 @@ namespace Microsoft.FSharp.Control
/// Legacy .NET Async Interoperability
///
///
- static member AsBeginEnd : computation:('Arg -> Async<'T>) ->
+ static member AsBeginEnd : computation:('Arg -> Async<'T>) ->
// The 'Begin' member
- ('Arg * System.AsyncCallback * obj -> System.IAsyncResult) *
+ ('Arg * System.AsyncCallback * obj -> System.IAsyncResult) *
// The 'End' member
- (System.IAsyncResult -> 'T) *
+ (System.IAsyncResult -> 'T) *
// The 'Cancel' member
(System.IAsyncResult -> unit)
- /// Creates an asynchronous computation that runs the given computation and ignores
+ /// Creates an asynchronous computation that runs the given computation and ignores
/// its result.
///
/// The input computation.
@@ -995,16 +1031,16 @@ namespace Microsoft.FSharp.Control
/// Starting Async Computations
///
///
- static member StartWithContinuations:
- computation:Async<'T> *
- continuation:('T -> unit) * exceptionContinuation:(exn -> unit) * cancellationContinuation:(OperationCanceledException -> unit) *
+ static member StartWithContinuations:
+ computation:Async<'T> *
+ continuation:('T -> unit) * exceptionContinuation:(exn -> unit) * cancellationContinuation:(OperationCanceledException -> unit) *
?cancellationToken:CancellationToken-> unit
///
///
- static member internal StartWithContinuationsUsingDispatchInfo:
- computation:Async<'T> *
- continuation:('T -> unit) * exceptionContinuation:(ExceptionDispatchInfo -> unit) * cancellationContinuation:(OperationCanceledException -> unit) *
+ static member internal StartWithContinuationsUsingDispatchInfo:
+ computation:Async<'T> *
+ continuation:('T -> unit) * exceptionContinuation:(ExceptionDispatchInfo -> unit) * cancellationContinuation:(OperationCanceledException -> unit) *
?cancellationToken:CancellationToken-> unit
/// Runs an asynchronous computation, starting immediately on the current operating system
@@ -1032,7 +1068,7 @@ namespace Microsoft.FSharp.Control
///
/// Prints "A", "B", "D" immediately, then "C" in 1 second
///
- static member StartImmediate:
+ static member StartImmediate:
computation:Async * ?cancellationToken:CancellationToken-> unit
/// Runs an asynchronous computation, starting immediately on the current operating system
@@ -1040,7 +1076,7 @@ namespace Microsoft.FSharp.Control
///
///
/// If no cancellation token is provided then the default cancellation token is used.
- /// You may prefer using this method if you want to achive a similar behviour to async await in C# as
+ /// You may prefer using this method if you want to achive a similar behviour to async await in C# as
/// async computation starts on the current thread with an ability to return a result.
///
///
@@ -1070,7 +1106,7 @@ namespace Microsoft.FSharp.Control
///
/// Prints "A", "B", "D" immediately, then "C", "E" in 1 second.
///
- static member StartImmediateAsTask:
+ static member StartImmediateAsTask:
computation:Async<'T> * ?cancellationToken:CancellationToken-> Task<'T>
@@ -1188,7 +1224,7 @@ namespace Microsoft.FSharp.Control
/// A value indicating asynchronous execution.
val TryWith: ctxt:AsyncActivation<'T> -> computation: Async<'T> -> catchFunction: (Exception -> Async<'T> option) -> AsyncReturn
- []
+ []
// Internals used by MailboxProcessor
type internal ResultCell<'T> =
new : unit -> ResultCell<'T>
@@ -1215,7 +1251,7 @@ namespace Microsoft.FSharp.Control
///
/// A cancellation check is performed on each iteration of the loop.
///
- /// The existence of this method permits the use of for in the
+ /// The existence of this method permits the use of for in the
/// async { ... } computation expression syntax.
///
/// The sequence to enumerate.
@@ -1232,19 +1268,19 @@ namespace Microsoft.FSharp.Control
///
/// A cancellation check is performed when the computation is executed.
///
- /// The existence of this method permits the use of empty else branches in the
+ /// The existence of this method permits the use of empty else branches in the
/// async { ... } computation expression syntax.
/// An asynchronous computation that returns ().
///
///
- member Zero : unit -> Async
+ member Zero : unit -> Async
/// Creates an asynchronous computation that first runs computation1
/// and then runs computation2, returning the result of computation2.
///
/// A cancellation check is performed when the computation is executed.
///
- /// The existence of this method permits the use of expression sequencing in the
+ /// The existence of this method permits the use of expression sequencing in the
/// async { ... } computation expression syntax.
///
/// The first part of the sequenced computation.
@@ -1255,12 +1291,12 @@ namespace Microsoft.FSharp.Control
///
member inline Combine : computation1:Async * computation2:Async<'T> -> Async<'T>
- /// Creates an asynchronous computation that runs computation repeatedly
+ /// Creates an asynchronous computation that runs computation repeatedly
/// until guard() becomes false.
///
/// A cancellation check is performed whenever the computation is executed.
///
- /// The existence of this method permits the use of while in the
+ /// The existence of this method permits the use of while in the
/// async { ... } computation expression syntax.
///
/// The function to determine when to stop executing computation.
@@ -1276,7 +1312,7 @@ namespace Microsoft.FSharp.Control
///
/// A cancellation check is performed when the computation is executed.
///
- /// The existence of this method permits the use of return in the
+ /// The existence of this method permits the use of return in the
/// async { ... } computation expression syntax.
///
/// The value to return from the computation.
@@ -1288,7 +1324,7 @@ namespace Microsoft.FSharp.Control
/// Delegates to the input computation.
///
- /// The existence of this method permits the use of return! in the
+ /// The existence of this method permits the use of return! in the
/// async { ... } computation expression syntax.
///
/// The input computation.
@@ -1309,13 +1345,13 @@ namespace Microsoft.FSharp.Control
///
member Delay : generator:(unit -> Async<'T>) -> Async<'T>
- /// Creates an asynchronous computation that runs binder(resource).
+ /// Creates an asynchronous computation that runs binder(resource).
/// The action resource.Dispose() is executed as this computation yields its result
/// or if the asynchronous computation exits by an exception or by cancellation.
///
/// A cancellation check is performed when the computation is executed.
///
- /// The existence of this method permits the use of use and use! in the
+ /// The existence of this method permits the use of use and use! in the
/// async { ... } computation expression syntax.
///
/// The resource to be used and disposed.
@@ -1327,12 +1363,12 @@ namespace Microsoft.FSharp.Control
///
member Using: resource:'T * binder:('T -> Async<'U>) -> Async<'U> when 'T :> System.IDisposable
- /// Creates an asynchronous computation that runs computation, and when
+ /// Creates an asynchronous computation that runs computation, and when
/// computation generates a result T, runs binder res.
///
/// A cancellation check is performed when the computation is executed.
///
- /// The existence of this method permits the use of let! in the
+ /// The existence of this method permits the use of let! in the
/// async { ... } computation expression syntax.
///
/// The computation to provide an unbound result.
@@ -1343,14 +1379,14 @@ namespace Microsoft.FSharp.Control
///
///
member inline Bind: computation: Async<'T> * binder: ('T -> Async<'U>) -> Async<'U>
-
- /// Creates an asynchronous computation that runs computation. The action compensation is executed
+
+ /// Creates an asynchronous computation that runs computation. The action compensation is executed
/// after computation completes, whether computation exits normally or by an exception. If compensation raises an exception itself
/// the original exception is discarded and the new exception becomes the overall result of the computation.
///
/// A cancellation check is performed when the computation is executed.
///
- /// The existence of this method permits the use of try/finally in the
+ /// The existence of this method permits the use of try/finally in the
/// async { ... } computation expression syntax.
///
/// The input computation.
@@ -1368,7 +1404,7 @@ namespace Microsoft.FSharp.Control
///
/// A cancellation check is performed when the computation is executed.
///
- /// The existence of this method permits the use of try/with in the
+ /// The existence of this method permits the use of try/with in the
/// async { ... } computation expression syntax.
///
/// The input computation.
@@ -1393,9 +1429,9 @@ namespace Microsoft.FSharp.Control
/// Async Programming
[]
module CommonExtensions =
-
- type System.IO.Stream with
-
+
+ type System.IO.Stream with
+
/// Returns an asynchronous computation that will read from the stream into the given buffer.
/// The buffer to read into.
/// An optional offset as a number of bytes in the stream.
@@ -1406,21 +1442,21 @@ namespace Microsoft.FSharp.Control
/// Thrown when the sum of offset and count is longer than
/// the buffer length.
/// Thrown when offset or count is negative.
- ///
+ ///
///
[] // give the extension member a nice, unmangled compiled name, unique within this module
member AsyncRead : buffer:byte[] * ?offset:int * ?count:int -> Async
-
+
/// Returns an asynchronous computation that will read the given number of bytes from the stream.
///
/// The number of bytes to read.
///
- /// An asynchronous computation that returns the read byte[] when run.
- ///
+ /// An asynchronous computation that returns the read byte[] when run.
+ ///
///
[] // give the extension member a nice, unmangled compiled name, unique within this module
member AsyncRead : count:int -> Async
-
+
/// Returns an asynchronous computation that will write the given bytes to the stream.
///
/// The buffer to write from.
@@ -1432,7 +1468,7 @@ namespace Microsoft.FSharp.Control
/// Thrown when the sum of offset and count is longer than
/// the buffer length.
/// Thrown when offset or count is negative.
- ///
+ ///
///
[] // give the extension member a nice, unmangled compiled name, unique within this module
member AsyncWrite : buffer:byte[] * ?offset:int * ?count:int -> Async
@@ -1444,7 +1480,7 @@ namespace Microsoft.FSharp.Control
/// be invoked for each observation.
///
/// The function to be called for each observation.
- ///
+ ///
///
[] // give the extension member a nice, unmangled compiled name, unique within this module
member Add: callback:('T -> unit) -> unit
@@ -1456,7 +1492,7 @@ namespace Microsoft.FSharp.Control
/// The function to be called for each observation.
///
/// An object that will remove the listener if disposed.
- ///
+ ///
///
[] // give the extension member a nice, unmangled compiled name, unique within this module
member Subscribe: callback:('T -> unit) -> System.IDisposable
@@ -1465,12 +1501,12 @@ namespace Microsoft.FSharp.Control
///
/// Async Programming
[]
- module WebExtensions =
+ module WebExtensions =
- type System.Net.WebRequest with
+ type System.Net.WebRequest with
/// Returns an asynchronous computation that, when run, will wait for a response to the given WebRequest.
/// An asynchronous computation that waits for response to the WebRequest.
- ///
+ ///
///
///
/// open System.Net
@@ -1493,7 +1529,7 @@ namespace Microsoft.FSharp.Control
/// The URI to retrieve.
///
/// An asynchronous computation that will wait for the download of the URI.
- ///
+ ///
///
///
/// open System
@@ -1510,14 +1546,14 @@ namespace Microsoft.FSharp.Control
/// The URI to retrieve.
///
/// An asynchronous computation that will wait for the download of the URI.
- ///
+ ///
///
///
/// open System.Net
/// open System.Text
/// open System
/// let client = new WebClient()
- /// client.AsyncDownloadData(Uri("https://www.w3.org")) |> Async.RunSynchronously |> Encoding.ASCII.GetString
+ /// client.AsyncDownloadData(Uri("https://www.w3.org")) |> Async.RunSynchronously |> Encoding.ASCII.GetString
///
///
/// Downloads the data in bytes and decodes it to a string.
@@ -1530,7 +1566,7 @@ namespace Microsoft.FSharp.Control
/// The file name to save download to.
///
/// An asynchronous computation that will wait for the download of the URI to specified file.
- ///
+ ///
///
///
/// open System.Net
@@ -1544,6 +1580,6 @@ namespace Microsoft.FSharp.Control
member AsyncDownloadFile : address:System.Uri * fileName: string -> Async
// Internals used by MailboxProcessor
- module internal AsyncBuilderImpl =
+ module internal AsyncBuilderImpl =
val async : AsyncBuilder
diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModule.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModule.fs
index 2edf022ac75..3f01fcb953e 100644
--- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModule.fs
+++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModule.fs
@@ -80,13 +80,13 @@ module ChoiceUtils =
let result =
let cancellationToken =
match cancelAfter with
- | Some ca ->
+ | Some ca ->
let cts = new CancellationTokenSource()
cts.CancelAfter(ca)
Some cts.Token
| None -> None
- try Async.RunSynchronously(choiceWorkflow, ?cancellationToken = cancellationToken) |> Choice1Of2
+ try Async.RunSynchronously(choiceWorkflow, ?cancellationToken = cancellationToken) |> Choice1Of2
with e -> Choice2Of2 e
// Step 3. check that results are up to spec
@@ -94,7 +94,7 @@ module ChoiceUtils =
seq {
yield Int32.MaxValue // "infinity": avoid exceptions if list is empty
- for op in ops do
+ for op in ops do
match op with
| NoneResultAfter _ -> ()
| op -> yield op.Timeout
@@ -105,7 +105,7 @@ module ChoiceUtils =
let verifyIndex index =
if index < 0 || index >= ops.Length then
Assert.Fail "Returned choice index is out of bounds."
-
+
// Step 3a. check that output is up to spec
match result with
| Choice1Of2 (Some index) ->
@@ -142,36 +142,36 @@ module LeakUtils =
// We also need something non trivial to dissuade the compiler from inlining in Release builds.
type ToRun<'a>(f : unit -> 'a) =
member _.Invoke() = f()
-
+
let run (toRun : ToRun<'a>) = toRun.Invoke()
// ---------------------------------------------------
type AsyncModule() =
-
+
/// Simple asynchronous task that delays 200ms and returns a list of the current tick count
let getTicksTask =
async {
do! Async.SwitchToThreadPool()
let mutable tickstamps = [] // like timestamps but for ticks :)
-
+
for i = 1 to 10 do
tickstamps <- DateTime.UtcNow.Ticks :: tickstamps
do! Async.Sleep(20)
-
+
return tickstamps
}
- let wait (wh : System.Threading.WaitHandle) (timeoutMilliseconds : int) =
+ let wait (wh : System.Threading.WaitHandle) (timeoutMilliseconds : int) =
wh.WaitOne(timeoutMilliseconds, exitContext=false)
let dispose(d : #IDisposable) = d.Dispose()
- let testErrorAndCancelRace testCaseName computation =
+ let testErrorAndCancelRace testCaseName computation =
for i in 1..20 do
let cts = new System.Threading.CancellationTokenSource()
use barrier = new System.Threading.ManualResetEvent(false)
- async { cts.Cancel() }
+ async { cts.Cancel() }
|> Async.Start
let c = ref 0
@@ -189,6 +189,25 @@ type AsyncModule() =
|> ignore
if c.Value = 2 then Assert.Fail("both error and cancel continuations were called")
+ []
+ member _.``Async.RunImmediate should execute on the same thread`` () =
+ let t =
+ async {
+ let a = Thread.CurrentThread.ManagedThreadId
+ let b =
+ async {
+ return Thread.CurrentThread.ManagedThreadId
+ } |> Async.RunImmediate
+ let c = Thread.CurrentThread.ManagedThreadId
+ return $"Before: {a}, in async: {b}, after async: {c}"
+ } |> Async.RunImmediate
+
+ let d = Thread.CurrentThread.ManagedThreadId
+ let actual = $"{t}, after task: {d}"
+
+ if not (actual = $"Before: {d}, in async: {d}, after async: {d}, after task: {d}") then
+ failwith actual
+
[]
member _.AwaitIAsyncResult() =
@@ -203,8 +222,8 @@ type AsyncModule() =
// When the operation has already completed
let operationIAR = beginOp ((), new AsyncCallback(fun iar -> ()), null)
sleep(250)
-
- let result = Async.AwaitIAsyncResult(operationIAR) |> Async.RunSynchronously
+
+ let result = Async.AwaitIAsyncResult(operationIAR) |> Async.RunSynchronously
match result with
| true -> ()
| false -> Assert.Fail("Timed out. Expected to succeed.")
@@ -217,11 +236,11 @@ type AsyncModule() =
| false -> ()
[]
- member _.``AwaitWaitHandle.Timeout``() =
+ member _.``AwaitWaitHandle.Timeout``() =
use waitHandle = new System.Threading.ManualResetEvent(false)
let startTime = DateTime.UtcNow
- let r =
+ let r =
Async.AwaitWaitHandle(waitHandle, 500)
|> Async.RunSynchronously
@@ -232,19 +251,19 @@ type AsyncModule() =
Assert.True(delta.TotalMilliseconds < 1100.0, sprintf "Expected faster timeout than %.0f ms" delta.TotalMilliseconds)
[]
- member _.``AwaitWaitHandle.TimeoutWithCancellation``() =
+ member _.``AwaitWaitHandle.TimeoutWithCancellation``() =
use barrier = new System.Threading.ManualResetEvent(false)
use waitHandle = new System.Threading.ManualResetEvent(false)
let cts = new System.Threading.CancellationTokenSource()
Async.AwaitWaitHandle(waitHandle, 5000)
|> Async.Ignore
- |> fun c ->
+ |> fun c ->
Async.StartWithContinuations(
- c,
- (failwithf "Unexpected success %A"),
- (failwithf "Unexpected error %A"),
- (fun _ -> barrier.Set() |> ignore),
+ c,
+ (failwithf "Unexpected success %A"),
+ (failwithf "Unexpected error %A"),
+ (fun _ -> barrier.Set() |> ignore),
cts.Token
)
@@ -259,9 +278,9 @@ type AsyncModule() =
if not ok then Assert.Fail("Async computation was not completed in given time")
[]
- member _.``AwaitWaitHandle.DisposedWaitHandle1``() =
+ member _.``AwaitWaitHandle.DisposedWaitHandle1``() =
let wh = new System.Threading.ManualResetEvent(false)
-
+
dispose wh
let test = async {
try
@@ -275,8 +294,8 @@ type AsyncModule() =
// test is flaky: https://github.com/dotnet/fsharp/issues/11586
//[]
- member _.``OnCancel.RaceBetweenCancellationHandlerAndDisposingHandlerRegistration``() =
- let test() =
+ member _.``OnCancel.RaceBetweenCancellationHandlerAndDisposingHandlerRegistration``() =
+ let test() =
use flag = new ManualResetEvent(false)
use cancelHandlerRegistered = new ManualResetEvent(false)
let cts = new System.Threading.CancellationTokenSource()
@@ -299,7 +318,7 @@ type AsyncModule() =
// test is flaky: https://github.com/dotnet/fsharp/issues/11586
//[]
- member _.``OnCancel.RaceBetweenCancellationAndDispose``() =
+ member _.``OnCancel.RaceBetweenCancellationAndDispose``() =
let mutable flag = 0
let cts = new System.Threading.CancellationTokenSource()
let go = async {
@@ -318,8 +337,8 @@ type AsyncModule() =
// test is flaky: https://github.com/dotnet/fsharp/issues/11586
//[]
- member _.``OnCancel.CancelThatWasSignalledBeforeRunningTheComputation``() =
- let test() =
+ member _.``OnCancel.CancelThatWasSignalledBeforeRunningTheComputation``() =
+ let test() =
let cts = new System.Threading.CancellationTokenSource()
let go e (flag : bool ref) = async {
let! _ = Async.AwaitWaitHandle e
@@ -347,13 +366,13 @@ type AsyncModule() =
// This test checks that AwaitWaitHandle does not leak continuations (described in #131),
// We only test the worst case - when the AwaitWaitHandle is already set.
use manualResetEvent = new System.Threading.ManualResetEvent(true)
-
- let tryToLeak() =
- let resource =
+
+ let tryToLeak() =
+ let resource =
LeakUtils.ToRun (fun () ->
let resource = obj()
- let work =
- async {
+ let work =
+ async {
let! _ = Async.AwaitWaitHandle manualResetEvent
GC.KeepAlive(resource)
return ()
@@ -372,13 +391,13 @@ type AsyncModule() =
GC.Collect()
Assert.False(resource.IsAlive)
-
+
// The leak hangs on a race condition which is really hard to trigger in F# 3.0, hence the 100000 runs...
for _ in 1..10 do tryToLeak()
#endif
[]
- member _.``AwaitWaitHandle.DisposedWaitHandle2``() =
+ member _.``AwaitWaitHandle.DisposedWaitHandle2``() =
let wh = new System.Threading.ManualResetEvent(false)
let barrier = new System.Threading.ManualResetEvent(false)
@@ -393,12 +412,12 @@ type AsyncModule() =
let timeout = wait barrier 3000
Assert.False(timeout, "Barrier was reached too early")
dispose wh
-
+
let ok = wait barrier 10000
if not ok then Assert.Fail("Async computation was not completed in given time")
[]
- member _.``RunSynchronously.NoThreadJumpsAndTimeout``() =
+ member _.``RunSynchronously.NoThreadJumpsAndTimeout``() =
let longRunningTask = async { sleep(5000) }
try
Async.RunSynchronously(longRunningTask, timeout = 500)
@@ -407,7 +426,7 @@ type AsyncModule() =
:? System.TimeoutException -> ()
[]
- member _.``RunSynchronously.NoThreadJumpsAndTimeout.DifferentSyncContexts``() =
+ member _.``RunSynchronously.NoThreadJumpsAndTimeout.DifferentSyncContexts``() =
let run syncContext =
let old = SynchronizationContext.Current
SynchronizationContext.SetSynchronizationContext(syncContext)
@@ -425,7 +444,7 @@ type AsyncModule() =
[]
// See https://github.com/dotnet/fsharp/issues/12637#issuecomment-1020199383
- member _.``RunSynchronously.ThreadJump.IfSyncCtxtNonNull``() =
+ member _.``RunSynchronously.ThreadJump.IfSyncCtxtNonNull``() =
async {
do! Async.SwitchToThreadPool()
let old = SynchronizationContext.Current
@@ -444,7 +463,7 @@ type AsyncModule() =
|> Async.RunSynchronously
[]
- member _.``RaceBetweenCancellationAndError.AwaitWaitHandle``() =
+ member _.``RaceBetweenCancellationAndError.AwaitWaitHandle``() =
let disposedEvent = new System.Threading.ManualResetEvent(false)
dispose disposedEvent
testErrorAndCancelRace "RaceBetweenCancellationAndError.AwaitWaitHandle" (Async.AwaitWaitHandle disposedEvent)
@@ -476,13 +495,13 @@ type AsyncModule() =
[]
member _.``error on one workflow should cancel all others``() =
- let counter =
+ let counter =
async {
let mutable counter = 0
- let job i = async {
- if i = 55 then failwith "boom"
- else
- do! Async.Sleep 1000
+ let job i = async {
+ if i = 55 then failwith "boom"
+ else
+ do! Async.Sleep 1000
counter <- counter + 1
}
@@ -494,7 +513,7 @@ type AsyncModule() =
Assert.AreEqual(0, counter)
[]
- member _.``AwaitWaitHandle.ExceptionsAfterTimeout``() =
+ member _.``AwaitWaitHandle.ExceptionsAfterTimeout``() =
let wh = new System.Threading.ManualResetEvent(false)
let test = async {
try
@@ -506,40 +525,40 @@ type AsyncModule() =
:? InvalidOperationException as e when e.Message = "EXPECTED" -> return ()
}
Async.RunSynchronously(test)
-
+
[]
- member _.``FromContinuationsCanTailCallCurrentThread``() =
+ member _.``FromContinuationsCanTailCallCurrentThread``() =
let mutable cnt = 0
- let origTid = System.Threading.Thread.CurrentThread.ManagedThreadId
+ let origTid = System.Threading.Thread.CurrentThread.ManagedThreadId
let mutable finalTid = -1
let rec f n =
if n = 0 then
- async {
+ async {
finalTid <- System.Threading.Thread.CurrentThread.ManagedThreadId
return () }
else
async {
cnt <- cnt + 1
do! Async.FromContinuations(fun (k,_,_) -> k())
- do! f (n-1)
+ do! f (n-1)
}
// 5000 is big enough that does-not-stackoverflow means we are tailcalling thru FromContinuations
- f 5000 |> Async.StartImmediate
+ f 5000 |> Async.StartImmediate
Assert.AreEqual(origTid, finalTid)
Assert.AreEqual(5000, cnt)
[]
- member _.``AwaitWaitHandle With Cancellation``() =
+ member _.``AwaitWaitHandle With Cancellation``() =
let run wh = async {
let! r = Async.AwaitWaitHandle wh
Assert.True(r, "Timeout not expected")
- return()
+ return()
}
- let test () =
+ let test () =
let wh = new System.Threading.ManualResetEvent(false)
let cts = new System.Threading.CancellationTokenSource()
let asyncs =
- [
+ [
yield! List.init 100 (fun _ -> run wh)
yield async { cts.Cancel() }
yield async { wh.Set() |> ignore }
@@ -554,7 +573,7 @@ type AsyncModule() =
for _ in 1..1000 do test()
[]
- member _.``StartWithContinuationsVersusDoBang``() =
+ member _.``StartWithContinuationsVersusDoBang``() =
// worthwhile to note these three
// case 1
let mutable r = ""
@@ -563,8 +582,8 @@ type AsyncModule() =
do! Async.FromContinuations(fun (s, _, _) -> s())
return failwith "boom"
with
- e-> r <- e.Message
- } |> Async.RunSynchronously
+ e-> r <- e.Message
+ } |> Async.RunSynchronously
Assert.AreEqual("boom", r)
// case 2
r <- ""
@@ -581,37 +600,37 @@ type AsyncModule() =
#if IGNORED
[]
- member _.``SleepContinuations``() =
+ member _.``SleepContinuations``() =
let okCount = ref 0
let errCount = ref 0
- let test() =
- let cts = new System.Threading.CancellationTokenSource()
-
- System.Threading.ThreadPool.QueueUserWorkItem(fun _->
- System.Threading.Thread.Sleep 50
- try
- Async.StartWithContinuations(
- Async.Sleep(1000),
- (fun _ -> printfn "ok"; incr okCount),
- (fun _ -> printfn "error"; incr errCount),
- (fun _ -> printfn "cancel"; failwith "BOOM!"),
- cancellationToken = cts.Token
- )
- with _ -> ()
- ) |> ignore
- System.Threading.Thread.Sleep 50
- try cts.Cancel() with _ -> ()
- System.Threading.Thread.Sleep 1500
- printfn "===="
+ let test() =
+ let cts = new System.Threading.CancellationTokenSource()
+
+ System.Threading.ThreadPool.QueueUserWorkItem(fun _->
+ System.Threading.Thread.Sleep 50
+ try
+ Async.StartWithContinuations(
+ Async.Sleep(1000),
+ (fun _ -> printfn "ok"; incr okCount),
+ (fun _ -> printfn "error"; incr errCount),
+ (fun _ -> printfn "cancel"; failwith "BOOM!"),
+ cancellationToken = cts.Token
+ )
+ with _ -> ()
+ ) |> ignore
+ System.Threading.Thread.Sleep 50
+ try cts.Cancel() with _ -> ()
+ System.Threading.Thread.Sleep 1500
+ printfn "===="
for i = 1 to 3 do test()
Assert.AreEqual(0, !okCount)
Assert.AreEqual(0, !errCount)
#endif
[]
- member _.``Async caching should work``() =
+ member _.``Async caching should work``() =
let mutable x = 0
- let someSlowFunc _mykey = async {
+ let someSlowFunc _mykey = async {
Console.WriteLine "Simulated downloading..."
do! Async.Sleep 400
Console.WriteLine "Simulated downloading Done."
@@ -625,7 +644,7 @@ type AsyncModule() =
do! memFunc "a" |> Async.Ignore
do! memFunc "a" |> Async.Ignore
do! memFunc "a" |> Async.Ignore
- do! [|1 .. 30|] |> Seq.map(fun _ -> (memFunc "a"))
+ do! [|1 .. 30|] |> Seq.map(fun _ -> (memFunc "a"))
|> Async.Parallel |> Async.Ignore
Console.WriteLine "Still more ways...."
@@ -640,7 +659,7 @@ type AsyncModule() =
Async.Start( memFunc "a" |> Async.Ignore )
Console.WriteLine "Still more ways again again...."
- do! [|1 .. 30|] |> Seq.map(fun _ -> (memFunc "a"))
+ do! [|1 .. 30|] |> Seq.map(fun _ -> (memFunc "a"))
|> Async.Parallel |> Async.Ignore
} |> Async.RunSynchronously
Console.WriteLine "Checking result...."
@@ -737,16 +756,16 @@ type AsyncModule() =
// index 1 will enter the try/finally quickly, call failwith and cancel the other tasks
// One of index 2 and index 3 will be stuck here before the try/finally. But having got
// this far it should enter the try/finally before cancellation takes effect
- do
+ do
lock gate <| fun () -> printfn "[%i] Acquired semaphore" index
Interlocked.Increment(&acquiredCount) |> ignore
- if index <> 0 then
+ if index <> 0 then
lock gate <| fun () -> printfn "[%i] Slowly entering try/finally" index
System.Threading.Thread.Sleep(100)
try
lock gate <| fun () -> printfn "[%i] Within try-finally" index
- if index = 0 then
+ if index = 0 then
lock gate <| fun () -> printfn "[%i] Error" index
// The failure will cause others to cancel
failwith "Something bad happened!"
diff --git a/tests/FSharp.Core.UnitTests/SurfaceArea.fs b/tests/FSharp.Core.UnitTests/SurfaceArea.fs
index fd0fe854332..2cb17b58b8f 100644
--- a/tests/FSharp.Core.UnitTests/SurfaceArea.fs
+++ b/tests/FSharp.Core.UnitTests/SurfaceArea.fs
@@ -606,6 +606,7 @@ Microsoft.FSharp.Control.FSharpAsync: System.Threading.CancellationToken get_Def
Microsoft.FSharp.Control.FSharpAsync: System.Threading.Tasks.Task`1[T] StartAsTask[T](Microsoft.FSharp.Control.FSharpAsync`1[T], Microsoft.FSharp.Core.FSharpOption`1[System.Threading.Tasks.TaskCreationOptions], Microsoft.FSharp.Core.FSharpOption`1[System.Threading.CancellationToken])
Microsoft.FSharp.Control.FSharpAsync: System.Threading.Tasks.Task`1[T] StartImmediateAsTask[T](Microsoft.FSharp.Control.FSharpAsync`1[T], Microsoft.FSharp.Core.FSharpOption`1[System.Threading.CancellationToken])
Microsoft.FSharp.Control.FSharpAsync: System.Tuple`3[Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`3[TArg,System.AsyncCallback,System.Object],System.IAsyncResult],Microsoft.FSharp.Core.FSharpFunc`2[System.IAsyncResult,T],Microsoft.FSharp.Core.FSharpFunc`2[System.IAsyncResult,Microsoft.FSharp.Core.Unit]] AsBeginEnd[TArg,T](Microsoft.FSharp.Core.FSharpFunc`2[TArg,Microsoft.FSharp.Control.FSharpAsync`1[T]])
+Microsoft.FSharp.Control.FSharpAsync: T RunImmediate[T](Microsoft.FSharp.Control.FSharpAsync`1[T], Microsoft.FSharp.Core.FSharpOption`1[System.Threading.CancellationToken])
Microsoft.FSharp.Control.FSharpAsync: T RunSynchronously[T](Microsoft.FSharp.Control.FSharpAsync`1[T], Microsoft.FSharp.Core.FSharpOption`1[System.Int32], Microsoft.FSharp.Core.FSharpOption`1[System.Threading.CancellationToken])
Microsoft.FSharp.Control.FSharpAsync: Void CancelDefaultToken()
Microsoft.FSharp.Control.FSharpAsync: Void Start(Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit], Microsoft.FSharp.Core.FSharpOption`1[System.Threading.CancellationToken])