From 9882614b936f5b0a32d092e926cc37b98ac412b6 Mon Sep 17 00:00:00 2001 From: Justin Wick Date: Wed, 1 Dec 2021 01:54:09 -0500 Subject: [PATCH 1/4] Initial set of examples for PR. --- src/FSharp.Core/async.fsi | 542 ++++++++++++++++++++++++++++++++------ 1 file changed, 460 insertions(+), 82 deletions(-) diff --git a/src/FSharp.Core/async.fsi b/src/FSharp.Core/async.fsi index a26c09b2156..89b8e874b35 100644 --- a/src/FSharp.Core/async.fsi +++ b/src/FSharp.Core/async.fsi @@ -51,7 +51,7 @@ namespace Microsoft.FSharp.Control /// /// 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 is started on the current thread if is null, @@ -73,8 +73,21 @@ namespace Microsoft.FSharp.Control /// The result of the computation. /// /// Starting Async Computations - /// - /// + /// + /// + /// + /// printfn "A" + /// + /// async { + /// printfn "B" + /// do! Async.Sleep(1000) + /// printfn "C" + /// } |> Async.RunSynchronously + /// + /// printfn "D" + /// + /// Prints "A", "B" immediately, then "C", "D" in 1 second. + /// static member RunSynchronously : computation:Async<'T> * ?timeout : int * ?cancellationToken:CancellationToken-> 'T /// Starts the asynchronous computation in the thread pool. Do not await its result. @@ -86,7 +99,21 @@ namespace Microsoft.FSharp.Control /// If one is not supplied, the default cancellation token is used. /// /// Starting Async Computations - /// + /// + /// + /// + /// printfn "A" + /// + /// async { + /// printfn "B" + /// do! Async.Sleep(1000) + /// printfn "C" + /// } |> Async.Start + /// + /// printfn "D" + /// + /// Prints "A", "D" immediately, then "B" quickly, and then "C" in 1 second. + /// /// static member Start : computation:Async * ?cancellationToken:CancellationToken -> unit @@ -98,14 +125,30 @@ namespace Microsoft.FSharp.Control /// in the corresponding state once the computation terminates (produces the result, throws exception or gets canceled) /// /// Starting Async Computations - /// - /// + /// + /// + /// + /// printfn "A" + /// + /// let t = + /// async { + /// printfn "B" + /// do! Async.Sleep(1000) + /// printfn "C" + /// } |> Async.StartAsTask + /// + /// printfn "D" + /// t.Wait() + /// printfn "E" + /// + /// Prints "A", "D" immediately, then "B" quickly, then "C", "E" in 1 second. + /// static member StartAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions * ?cancellationToken:CancellationToken -> Task<'T> /// Creates an asynchronous computation which starts the given computation as a /// /// Starting Async Computations - /// + /// /// static member StartChildAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions -> Async> @@ -119,8 +162,18 @@ namespace Microsoft.FSharp.Control /// A computation that returns a choice of type T or exception. /// /// Cancellation and Exceptions - /// - /// + /// + /// + /// + /// async { return someRiskyBusiness() } + /// |> Async.Catch + /// |> Async.RunSynchronously + /// |> function + /// | Choice1Of2 result -> printfn $"Result: {result}" + /// | Choice2Of2 e -> printfn $"Exception: {e}" + /// + /// Prints the returned value of someRiskyBusiness() or the exception if there is one. + /// static member Catch : computation:Async<'T> -> Async> /// Creates an asynchronous computation that executes computation. @@ -134,8 +187,28 @@ namespace Microsoft.FSharp.Control /// is cancelled. /// /// Cancellation and Exceptions - /// - /// + /// + /// + /// + /// [ 2; 3; 5; 7; 11 ] + /// |> List.map + /// (fun i -> + /// Async.TryCancelled( + /// async { + /// do! Async.Sleep(i * 1000) + /// printfn $"{i}" + /// }, + /// fun oce -> printfn $"Computation Cancelled: {i}" + /// )) + /// |> List.iter Async.Start + /// + /// Thread.Sleep(6000) + /// Async.CancelDefaultToken() + /// printfn "Tasks Finished" + /// + /// This will print "2" 2 seconds from start, "3" 3 seconds from start, "5" 5 seconds from start, cease computation + /// and then print "Computation Cancelled: 7", "Computation Cancelled: 11" and "Tasks Finished" in any order. + /// static member TryCancelled : computation:Async<'T> * compensation:(OperationCanceledException -> unit) -> Async<'T> /// Generates a scoped, cooperative cancellation handler for use within an asynchronous workflow. @@ -155,8 +228,25 @@ namespace Microsoft.FSharp.Control /// before being disposed. /// /// Cancellation and Exceptions - /// - /// + /// + /// + /// + /// [ 2; 3; 5; 7; 11 ] + /// |> List.iter + /// (fun i -> + /// async { + /// use! holder = Async.OnCancel(fun () -> printfn $"Computation Cancelled: {i}") + /// do! Async.Sleep(i * 1000) + /// printfn $"{i}" + /// } |> Async.Start) + /// + /// Thread.Sleep(6000) + /// Async.CancelDefaultToken() + /// printfn "Tasks Finished" + /// + /// This will print "2" 2 seconds from start, "3" 3 seconds from start, "5" 5 seconds from start, cease computation + /// 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 @@ -169,7 +259,7 @@ namespace Microsoft.FSharp.Control /// expression. /// /// Cancellation and Exceptions - /// + /// /// static member CancellationToken : Async @@ -179,8 +269,32 @@ namespace Microsoft.FSharp.Control /// specific CancellationToken. /// /// Cancellation and Exceptions - /// - /// + /// + /// + /// + /// try + /// let computations = + /// [ 2; 3; 5; 7; 11 ] + /// |> List.map + /// (fun i -> + /// async { + /// do! Async.Sleep(i * 1000) + /// printfn $"{i}" + /// }) + /// + /// let t = + /// Async.Parallel(computations, 3) + /// |> Async.StartAsTask + /// + /// Thread.Sleep(6000) + /// Async.CancelDefaultToken() + /// printfn $"Tasks Finished: %A{t.Result}" + /// with + /// | :? System.AggregateException as ae -> printfn $"Tasks Not Finished: {ae.Message}" + /// + /// 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 /// Gets the default cancellation token for executing asynchronous computations. @@ -188,15 +302,33 @@ namespace Microsoft.FSharp.Control /// The default CancellationToken. /// /// Cancellation and Exceptions - /// - /// + /// + /// + /// + /// Async.DefaultCancellationToken.Register(fun () -> printfn "Computation Cancelled") |> ignore + /// [ 2; 3; 5; 7; 11 ] + /// |> List.map + /// (fun i -> + /// async { + /// do! Async.Sleep(i * 1000) + /// printfn $"{i}" + /// }) + /// |> List.iter Async.Start + /// + /// Thread.Sleep(6000) + /// Async.CancelDefaultToken() + /// printfn "Tasks Finished" + /// + /// This will print "2" 2 seconds from start, "3" 3 seconds from start, "5" 5 seconds from start, cease computation and then + /// print "Computation Cancelled", followed by "Tasks Finished". + /// static member DefaultCancellationToken : CancellationToken //---------- Parallelism /// 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 /// right-hand-side of a let! binding in an F# asynchronous workflow, that is, /// @@ -208,7 +340,7 @@ namespace Microsoft.FSharp.Control /// let! result2 = completor2 /// ... } /// - /// + /// /// 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. @@ -220,15 +352,43 @@ namespace Microsoft.FSharp.Control /// A new computation that waits for the input computation to finish. /// /// Cancellation and Exceptions - /// - /// + /// + /// + /// + /// let computeWithTimeout timeout = + /// async { + /// let! completor1 = + /// Async.StartChild( + /// (async { + /// do! Async.Sleep(1000) + /// return 1 + /// }), + /// millisecondsTimeout = timeout + /// ) + /// + /// let! completor2 = + /// Async.StartChild( + /// (async { + /// do! Async.Sleep(2000) + /// return 2 + /// }), + /// millisecondsTimeout = timeout + /// ) + /// + /// let! v1 = completor1 + /// let! v2 = completor2 + /// printfn $"Result: {v1 + v2}" + /// } |> Async.RunSynchronously + /// + /// 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, /// 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. /// @@ -241,8 +401,30 @@ namespace Microsoft.FSharp.Control /// A computation that returns an array of values from the sequence of input computations. /// /// Composing Async Computations - /// - /// + /// + /// + /// + /// let t = + /// [ 2; 3; 5; 7; 10; 11 ] + /// |> List.map + /// (fun i -> + /// async { + /// do! Async.Sleep(System.Random().Next(1000, 2000)) + /// + /// if i % 2 > 0 then + /// printfn $"{i}" + /// return true + /// else + /// return false + /// }) + /// |> Async.Parallel + /// |> Async.StartAsTask + /// + /// t.Wait() + /// printfn $"%A{t.Result}" + /// + /// This will print "3", "5", "7", "11" (in any order) in 1-2 seconds and then [| false; true; true; true; false; true |]. + /// static member Parallel : computations:seq> -> Async<'T[]> /// Creates an asynchronous computation that executes all the given asynchronous computations, @@ -263,8 +445,34 @@ namespace Microsoft.FSharp.Control /// A computation that returns an array of values from the sequence of input computations. /// /// Composing Async Computations - /// - /// + /// + /// + /// + /// let computations = + /// [ 2; 3; 5; 7; 10; 11 ] + /// |> List.map + /// (fun i -> + /// async { + /// do! Async.Sleep(System.Random().Next(1000, 2000)) + /// + /// return + /// if i % 2 > 0 then + /// printfn $"{i}" + /// true + /// else + /// false + /// }) + /// + /// let t = + /// Async.Parallel(computations, 3) + /// |> Async.StartAsTask + /// + /// t.Wait() + /// printfn $"%A{t.Result}" + /// + /// This will print "3", "5" (in any order) in 1-2 seconds, and then "7", "11" (in any order) in 1-2 more seconds and then + /// [| false; true; true; true; false; true |]. + /// static member Parallel : computations:seq> * ?maxDegreeOfParallelism : int -> Async<'T[]> /// Creates an asynchronous computation that executes all the given asynchronous computations sequentially. @@ -283,8 +491,33 @@ namespace Microsoft.FSharp.Control /// A computation that returns an array of values from the sequence of input computations. /// /// Composing Async Computations - /// - /// + /// + /// + /// + /// let computations = + /// [ 2; 3; 5; 7; 10; 11 ] + /// |> List.map + /// (fun i -> + /// async { + /// do! Async.Sleep(System.Random().Next(1000, 2000)) + /// + /// if i % 2 > 0 then + /// printfn $"{i}" + /// return true + /// else + /// return false + /// }) + /// + /// let t = + /// Async.Sequential(computations) + /// |> Async.StartAsTask + /// + /// t.Wait() + /// 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 |]. + /// static member Sequential : computations:seq> -> Async<'T[]> /// Creates an asynchronous computation that executes all given asynchronous computations in parallel, @@ -304,8 +537,49 @@ namespace Microsoft.FSharp.Control /// A computation that returns the first succeeding computation. /// /// Composing Async Computations - /// - /// + /// + /// + /// + /// printfn "Starting" + /// [ 2; 3; 5; 7 ] + /// |> List.map + /// (fun i -> + /// async { + /// do! Async.Sleep(System.Random().Next(1000, 2000)) + /// return if i % 2 > 0 then Some(i) else None + /// }) + /// |> Async.Choice + /// |> Async.RunSynchronously + /// |> function + /// | Some (i) -> printfn $"{i}" + /// | None -> printfn "No Result" + /// + /// Prints one randomly selected odd number in 1-2 seconds. If the list is changed to all even numbers, it will + /// instead print "No Result". + /// + /// + /// + /// + /// [ 2; 3; 5; 7 ] + /// |> List.map + /// (fun i -> + /// async { + /// do! Async.Sleep(System.Random().Next(1000, 2000)) + /// + /// return + /// if i % 2 > 0 then + /// Some(i) + /// else + /// failwith $"Even numbers not supported: {i}" + /// }) + /// |> Async.Choice + /// |> Async.RunSynchronously + /// |> function + /// | Some (i) -> printfn $"{i}" + /// | None -> printfn "No Result" + /// + /// Will sometimes print one randomly selected odd number, sometimes throw System.Exception("Even numbers not supported: 2"). + /// static member Choice : computations:seq> -> Async<'T option> //---------- Thread Control @@ -316,8 +590,16 @@ namespace Microsoft.FSharp.Control /// A computation that will execute on a new thread. /// /// Threads and Contexts - /// - /// + /// + /// + /// + /// async { + /// do! Async.SwitchToNewThread() + /// do! someLongRunningComputation() + /// } |> Async.StartImmediate + /// + /// This will run someLongRunningComputation() without blocking the threads in the threadpool. + /// static member SwitchToNewThread : unit -> Async /// Creates an asynchronous computation that queues a work item that runs @@ -326,8 +608,21 @@ namespace Microsoft.FSharp.Control /// A computation that generates a new work item in the thread pool. /// /// Threads and Contexts - /// - /// + /// + /// + /// + /// async { + /// do! Async.SwitchToNewThread() + /// do! someLongRunningComputation() + /// do! Async.SwitchToThreadPool() + /// + /// for i in 1 .. 10 do + /// do! someShortRunningComputation() + /// } |> Async.StartImmediate + /// + /// 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 /// Creates an asynchronous computation that runs @@ -339,7 +634,7 @@ namespace Microsoft.FSharp.Control /// An asynchronous computation that uses the syncContext context to execute. /// /// Threads and Contexts - /// + /// /// static member SwitchToContext : syncContext:System.Threading.SynchronizationContext -> Async @@ -353,8 +648,28 @@ namespace Microsoft.FSharp.Control /// An asynchronous computation that provides the callback with the current continuations. /// /// Composing Async Computations - /// - /// + /// + /// + /// + /// let computation = + /// (fun (successCont, exceptionCont, cancellationCont) -> + /// try + /// someRiskyBusiness () |> successCont + /// with + /// | :? OperationCanceledException as oce -> cancellationCont oce + /// | e -> exceptionCont e) + /// |> Async.FromContinuations + /// + /// Async.StartWithContinuations( + /// computation, + /// (fun result -> printfn $"Result: {result}"), + /// (fun e -> printfn $"Exception: {e}"), + /// (fun oce -> printfn $"Cancelled: {oce}") + /// ) + /// + /// This anonymous function will call someRiskyBusiness() and be a good citizen with regards to the continuations + /// defined to report the outcome. + /// 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 @@ -364,7 +679,7 @@ namespace Microsoft.FSharp.Control /// 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 /// to cancel immediately. /// @@ -375,7 +690,7 @@ namespace Microsoft.FSharp.Control /// An asynchronous computation that waits for the event to be invoked. /// /// Awaiting Results - /// + /// /// static member AwaitEvent: event:IEvent<'Del,'T> * ?cancelAction : (unit -> unit) -> Async<'T> when 'Del : delegate<'T,unit> and 'Del :> System.Delegate @@ -390,7 +705,7 @@ namespace Microsoft.FSharp.Control /// An asynchronous computation that waits on the given WaitHandle. /// /// Awaiting Results - /// + /// /// static member AwaitWaitHandle: waitHandle: WaitHandle * ?millisecondsTimeout:int -> Async @@ -405,7 +720,7 @@ namespace Microsoft.FSharp.Control /// An asynchronous computation that waits on the given IAsyncResult. /// /// Awaiting Results - /// + /// /// static member AwaitIAsyncResult: iar: System.IAsyncResult * ?millisecondsTimeout:int -> Async @@ -416,7 +731,7 @@ namespace Microsoft.FSharp.Control /// /// If an exception occurs in the asynchronous computation then an exception is re-raised by this /// function. - /// + /// /// If the task is cancelled then is raised. Note /// that the task may be governed by a different cancellation token to the overall async computation /// where the AwaitTask occurs. In practice you should normally start the task with the @@ -426,7 +741,7 @@ namespace Microsoft.FSharp.Control /// /// /// Awaiting Results - /// + /// /// static member AwaitTask: task: Task<'T> -> Async<'T> @@ -437,7 +752,7 @@ namespace Microsoft.FSharp.Control /// /// If an exception occurs in the asynchronous computation then an exception is re-raised by this /// function. - /// + /// /// If the task is cancelled then is raised. Note /// that the task may be governed by a different cancellation token to the overall async computation /// where the AwaitTask occurs. In practice you should normally start the task with the @@ -447,7 +762,7 @@ namespace Microsoft.FSharp.Control /// /// /// Awaiting Results - /// + /// /// static member AwaitTask: task: Task -> Async @@ -465,8 +780,19 @@ namespace Microsoft.FSharp.Control /// and not infinite. /// /// Awaiting Results - /// - /// + /// + /// + /// + /// async { + /// printfn "A" + /// do! Async.Sleep(1000) + /// printfn "B" + /// } |> Async.Start + /// + /// printfn "C" + /// + /// Prints "C", then "A" quickly, and then "B" 1 second later + /// static member Sleep: millisecondsDueTime:int -> Async /// @@ -482,8 +808,18 @@ namespace Microsoft.FSharp.Control /// Thrown when the due time is negative. /// /// Awaiting Results - /// - /// + /// + /// + /// + /// async { + /// printfn "A" + /// do! Async.Sleep(TimeSpan(0, 0, 1)) + /// printfn "B" + /// } |> Async.Start + /// printfn "C" + /// + /// Prints "C", then "A" quickly, and then "B" 1 second later. + /// static member Sleep: dueTime:TimeSpan -> Async /// @@ -495,7 +831,7 @@ namespace Microsoft.FSharp.Control /// 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 /// executed, and the computation continues to wait for the completion of the operation. - /// + /// /// If cancelAction is not specified, then cancellation causes the computation /// to stop immediately, and subsequent invocations of the callback are ignored. /// @@ -506,7 +842,7 @@ namespace Microsoft.FSharp.Control /// An asynchronous computation wrapping the given Begin/End functions. /// /// Legacy .NET Async Interoperability - /// + /// /// static member FromBeginEnd : beginAction:(System.AsyncCallback * obj -> System.IAsyncResult) * endAction:(System.IAsyncResult -> 'T) * ?cancelAction : (unit -> unit) -> Async<'T> @@ -531,7 +867,7 @@ namespace Microsoft.FSharp.Control /// An asynchronous computation wrapping the given Begin/End functions. /// /// Legacy .NET Async Interoperability - /// + /// /// static member FromBeginEnd : arg:'Arg1 * beginAction:('Arg1 * System.AsyncCallback * obj -> System.IAsyncResult) * endAction:(System.IAsyncResult -> 'T) * ?cancelAction : (unit -> unit) -> Async<'T> @@ -542,7 +878,7 @@ namespace Microsoft.FSharp.Control /// 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 /// executed, and the computation continues to wait for the completion of the operation. - /// + /// /// If cancelAction is not specified, then cancellation causes the computation /// to stop immediately, and subsequent invocations of the callback are ignored. /// @@ -555,7 +891,7 @@ namespace Microsoft.FSharp.Control /// An asynchronous computation wrapping the given Begin/End functions. /// /// Legacy .NET Async Interoperability - /// + /// /// static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * beginAction:('Arg1 * 'Arg2 * System.AsyncCallback * obj -> System.IAsyncResult) * endAction:(System.IAsyncResult -> 'T) * ?cancelAction : (unit -> unit) -> Async<'T> @@ -565,7 +901,7 @@ namespace Microsoft.FSharp.Control /// 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 /// executed, and the computation continues to wait for the completion of the operation. - /// + /// /// If cancelAction is not specified, then cancellation causes the computation /// to stop immediately, and subsequent invocations of the callback are ignored. /// @@ -579,7 +915,7 @@ namespace Microsoft.FSharp.Control /// An asynchronous computation wrapping the given Begin/End functions. /// /// Legacy .NET Async Interoperability - /// + /// /// 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> @@ -592,7 +928,7 @@ namespace Microsoft.FSharp.Control /// A tuple of the begin, end, and cancel members. /// /// Legacy .NET Async Interoperability - /// + /// /// static member AsBeginEnd : computation:('Arg -> Async<'T>) -> // The 'Begin' member @@ -610,8 +946,21 @@ namespace Microsoft.FSharp.Control /// A computation that is equivalent to the input computation, but disregards the result. /// /// Composing Async Computations - /// - /// + /// + /// + /// + /// let readFile filename numBytes = + /// async { + /// use file = System.IO.File.OpenRead(filename) + /// printfn "Reading from file %s." filename + /// // Throw away the data being read. + /// do! file.AsyncRead(numBytes) |> Async.Ignore + /// } + /// readFile "example.txt" 42 |> Async.Start + /// + /// Reads bytes from a given file asynchronously and then ignores the result, allowing the do! to be used with functions + /// that return an unwanted value. + /// static member Ignore : computation: Async<'T> -> Async /// Runs an asynchronous computation, starting immediately on the current operating system @@ -628,14 +977,14 @@ namespace Microsoft.FSharp.Control /// The default is used if this parameter is not provided. /// /// Starting Async Computations - /// + /// /// 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> * @@ -652,8 +1001,21 @@ namespace Microsoft.FSharp.Control /// The default is used if this parameter is not provided. /// /// Starting Async Computations - /// - /// + /// + /// + /// + /// printfn "A" + /// + /// async { + /// printfn "B" + /// do! Async.Sleep(1000) + /// printfn "C" + /// } |> Async.StartImmediate + /// + /// printfn "D" + /// + /// Prints "A", "B", "D" immediately, then "C" in 1 second + /// static member StartImmediate: computation:Async * ?cancellationToken:CancellationToken-> unit @@ -674,8 +1036,24 @@ namespace Microsoft.FSharp.Control /// in the corresponding state once the computation terminates (produces the result, throws exception or gets canceled) /// /// Starting Async Computations - /// - /// + /// + /// + /// + /// printfn "A" + /// + /// let t = + /// async { + /// printfn "B" + /// do! Async.Sleep(1000) + /// printfn "C" + /// } |> Async.StartImmediateAsTask + /// + /// printfn "D" + /// t.Wait() + /// printfn "E" + /// + /// Prints "A", "B", "D" immediately, then "C", "E" in 1 second. + /// static member StartImmediateAsTask: computation:Async<'T> * ?cancellationToken:CancellationToken-> Task<'T> @@ -694,33 +1072,33 @@ namespace Microsoft.FSharp.Control /// The F# compiler emits calls to this function to implement F# async expressions. /// /// A value indicating asynchronous execution. - /// + /// /// member IsCancellationRequested: bool /// The F# compiler emits calls to this function to implement F# async expressions. /// /// A value indicating asynchronous execution. - /// + /// /// static member Success: AsyncActivation<'T> -> result: 'T -> AsyncReturn /// The F# compiler emits calls to this function to implement F# async expressions. /// /// A value indicating asynchronous execution. - /// + /// /// member OnSuccess: result: 'T -> AsyncReturn /// The F# compiler emits calls to this function to implement F# async expressions. - /// + /// /// member OnExceptionRaised: unit -> unit /// The F# compiler emits calls to this function to implement F# async expressions. /// /// A value indicating asynchronous execution. - /// + /// /// member OnCancellation: unit -> AsyncReturn @@ -830,7 +1208,7 @@ namespace Microsoft.FSharp.Control /// /// An asynchronous computation that will enumerate the sequence and run body /// for each element. - /// + /// /// member For: sequence:seq<'T> * body:('T -> Async) -> Async @@ -841,7 +1219,7 @@ namespace Microsoft.FSharp.Control /// 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 @@ -857,7 +1235,7 @@ namespace Microsoft.FSharp.Control /// The second part of the sequenced computation. /// /// An asynchronous computation that runs both of the computations sequentially. - /// + /// /// member inline Combine : computation1:Async * computation2:Async<'T> -> Async<'T> @@ -874,7 +1252,7 @@ namespace Microsoft.FSharp.Control /// of a while expression. /// /// An asynchronous computation that behaves similarly to a while loop when run. - /// + /// /// member While : guard:(unit -> bool) * computation:Async -> Async @@ -888,7 +1266,7 @@ namespace Microsoft.FSharp.Control /// The value to return from the computation. /// /// An asynchronous computation that returns value when executed. - /// + /// /// member inline Return : value:'T -> Async<'T> @@ -900,7 +1278,7 @@ namespace Microsoft.FSharp.Control /// The input computation. /// /// The input computation. - /// + /// /// member inline ReturnFrom : computation:Async<'T> -> Async<'T> @@ -911,7 +1289,7 @@ namespace Microsoft.FSharp.Control /// The function to run. /// /// An asynchronous computation that runs generator. - /// + /// /// member Delay : generator:(unit -> Async<'T>) -> Async<'T> @@ -929,7 +1307,7 @@ namespace Microsoft.FSharp.Control /// computation. /// /// An asynchronous computation that binds and eventually disposes resource. - /// + /// /// member Using: resource:'T * binder:('T -> Async<'U>) -> Async<'U> when 'T :> System.IDisposable @@ -946,7 +1324,7 @@ namespace Microsoft.FSharp.Control /// /// An asynchronous computation that performs a monadic bind on the result /// of computation. - /// + /// /// member inline Bind: computation: Async<'T> * binder: ('T -> Async<'U>) -> Async<'U> @@ -965,7 +1343,7 @@ namespace Microsoft.FSharp.Control /// /// An asynchronous computation that executes computation and compensation afterwards or /// when an exception is raised. - /// + /// /// member inline TryFinally : computation:Async<'T> * compensation:(unit -> unit) -> Async<'T> @@ -982,7 +1360,7 @@ namespace Microsoft.FSharp.Control /// /// An asynchronous computation that executes computation and calls catchHandler if an /// exception is thrown. - /// + /// /// member inline TryWith : computation:Async<'T> * catchHandler:(exn -> Async<'T>) -> Async<'T> From f16b7e1401129ec5e9d4e3f848995bf8846f2136 Mon Sep 17 00:00:00 2001 From: Justin Wick Date: Thu, 16 Dec 2021 22:41:28 -0500 Subject: [PATCH 2/4] PR feedback from @dsyme, 1 --- src/FSharp.Core/async.fsi | 121 +++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 59 deletions(-) diff --git a/src/FSharp.Core/async.fsi b/src/FSharp.Core/async.fsi index 89b8e874b35..cedc099bbae 100644 --- a/src/FSharp.Core/async.fsi +++ b/src/FSharp.Core/async.fsi @@ -78,15 +78,16 @@ namespace Microsoft.FSharp.Control /// /// printfn "A" /// - /// async { + /// let result = async { /// printfn "B" /// do! Async.Sleep(1000) /// printfn "C" + /// 17 /// } |> Async.RunSynchronously /// /// printfn "D" /// - /// Prints "A", "B" immediately, then "C", "D" in 1 second. + /// 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 @@ -112,7 +113,7 @@ namespace Microsoft.FSharp.Control /// /// printfn "D" /// - /// Prints "A", "D" immediately, then "B" quickly, and then "C" in 1 second. + /// Prints "A", then "D", "B" quickly in any order, and then "C" in 1 second. /// /// static member Start : computation:Async * ?cancellationToken:CancellationToken -> unit @@ -141,7 +142,7 @@ namespace Microsoft.FSharp.Control /// t.Wait() /// printfn "E" /// - /// Prints "A", "D" immediately, then "B" quickly, then "C", "E" in 1 second. + /// Prints "A", then "D", "B" quickly in any order, then "C", "E" in 1 second. /// static member StartAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions * ?cancellationToken:CancellationToken -> Task<'T> @@ -165,6 +166,11 @@ namespace Microsoft.FSharp.Control /// /// /// + /// let someRiskyBusiness() = + /// match DateTime.Today with + /// | dt when dt.DayOfWeek = DayOfWeek.Monday -> failwith "Not compatible with Mondays" + /// | dt -> dt + /// /// async { return someRiskyBusiness() } /// |> Async.Catch /// |> Async.RunSynchronously @@ -191,15 +197,13 @@ namespace Microsoft.FSharp.Control /// /// /// [ 2; 3; 5; 7; 11 ] - /// |> List.map - /// (fun i -> - /// Async.TryCancelled( - /// async { - /// do! Async.Sleep(i * 1000) - /// printfn $"{i}" - /// }, - /// fun oce -> printfn $"Computation Cancelled: {i}" - /// )) + /// |> List.map (fun i -> + /// Async.TryCancelled( + /// async { + /// do! Async.Sleep(i * 1000) + /// printfn $"{i}" + /// }, + /// fun oce -> printfn $"Computation Cancelled: {i}")) /// |> List.iter Async.Start /// /// Thread.Sleep(6000) @@ -232,13 +236,12 @@ namespace Microsoft.FSharp.Control /// /// /// [ 2; 3; 5; 7; 11 ] - /// |> List.iter - /// (fun i -> - /// async { - /// use! holder = Async.OnCancel(fun () -> printfn $"Computation Cancelled: {i}") - /// do! Async.Sleep(i * 1000) - /// printfn $"{i}" - /// } |> Async.Start) + /// |> List.iter (fun i -> + /// async { + /// use! holder = Async.OnCancel(fun () -> printfn $"Computation Cancelled: {i}") + /// do! Async.Sleep(i * 1000) + /// printfn $"{i}" + /// } |> Async.Start) /// /// Thread.Sleep(6000) /// Async.CancelDefaultToken() @@ -275,16 +278,14 @@ namespace Microsoft.FSharp.Control /// try /// let computations = /// [ 2; 3; 5; 7; 11 ] - /// |> List.map - /// (fun i -> - /// async { - /// do! Async.Sleep(i * 1000) - /// printfn $"{i}" - /// }) + /// |> List.map (fun i -> + /// async { + /// do! Async.Sleep(i * 1000) + /// printfn $"{i}" + /// }) /// /// let t = - /// Async.Parallel(computations, 3) - /// |> Async.StartAsTask + /// Async.Parallel(computations, 3) |> Async.StartAsTask /// /// Thread.Sleep(6000) /// Async.CancelDefaultToken() @@ -307,12 +308,11 @@ namespace Microsoft.FSharp.Control /// /// Async.DefaultCancellationToken.Register(fun () -> printfn "Computation Cancelled") |> ignore /// [ 2; 3; 5; 7; 11 ] - /// |> List.map - /// (fun i -> - /// async { - /// do! Async.Sleep(i * 1000) - /// printfn $"{i}" - /// }) + /// |> List.map (fun i -> + /// async { + /// do! Async.Sleep(i * 1000) + /// printfn $"{i}" + /// }) /// |> List.iter Async.Start /// /// Thread.Sleep(6000) @@ -356,29 +356,27 @@ namespace Microsoft.FSharp.Control /// /// /// let computeWithTimeout timeout = - /// async { - /// let! completor1 = - /// Async.StartChild( - /// (async { - /// do! Async.Sleep(1000) - /// return 1 - /// }), - /// millisecondsTimeout = timeout - /// ) - /// - /// let! completor2 = - /// Async.StartChild( - /// (async { - /// do! Async.Sleep(2000) - /// return 2 - /// }), - /// millisecondsTimeout = timeout - /// ) - /// - /// let! v1 = completor1 - /// let! v2 = completor2 - /// printfn $"Result: {v1 + v2}" - /// } |> Async.RunSynchronously + /// async { + /// let! completor1 = + /// Async.StartChild( + /// (async { + /// do! Async.Sleep(1000) + /// return 1 + /// }), + /// millisecondsTimeout = timeout) + /// + /// let! completor2 = + /// Async.StartChild( + /// (async { + /// do! Async.Sleep(2000) + /// return 2 + /// }), + /// millisecondsTimeout = timeout) + /// + /// let! v1 = completor1 + /// let! v2 = completor2 + /// printfn $"Result: {v1 + v2}" + /// } |> Async.RunSynchronously /// /// Will throw a System.TimeoutException if called with a timeout less than 2000, otherwise will print "Result: 3". /// @@ -464,7 +462,7 @@ namespace Microsoft.FSharp.Control /// }) /// /// let t = - /// Async.Parallel(computations, 3) + /// Async.Parallel(computations, maxDegreeOfParallelism=3) /// |> Async.StartAsTask /// /// t.Wait() @@ -651,6 +649,11 @@ namespace Microsoft.FSharp.Control /// /// /// + /// let someRiskyBusiness() = + /// match DateTime.Today with + /// | dt when dt.DayOfWeek = DayOfWeek.Monday -> failwith "Not compatible with Mondays" + /// | dt -> dt + /// /// let computation = /// (fun (successCont, exceptionCont, cancellationCont) -> /// try @@ -667,7 +670,7 @@ namespace Microsoft.FSharp.Control /// (fun oce -> printfn $"Cancelled: {oce}") /// ) /// - /// This anonymous function will call someRiskyBusiness() and be a good citizen with regards to the continuations + /// This anonymous function will call someRiskyBusiness() and properly use the provided continuations /// defined to report the outcome. /// static member FromContinuations : callback:(('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T> From 98d727a202b1e9b0e57be30b280573efd5f2e940 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Fri, 23 Sep 2022 20:12:41 +0100 Subject: [PATCH 3/4] Update async.fsi --- src/FSharp.Core/async.fsi | 126 ++++++++++++++++++++------------------ 1 file changed, 68 insertions(+), 58 deletions(-) diff --git a/src/FSharp.Core/async.fsi b/src/FSharp.Core/async.fsi index cedc099bbae..d88708015c1 100644 --- a/src/FSharp.Core/async.fsi +++ b/src/FSharp.Core/async.fsi @@ -196,15 +196,15 @@ namespace Microsoft.FSharp.Control /// /// /// - /// [ 2; 3; 5; 7; 11 ] - /// |> List.map (fun i -> + /// let primes = [ 2; 3; 5; 7; 11 ] + /// for i in primes do /// Async.TryCancelled( /// async { /// do! Async.Sleep(i * 1000) /// printfn $"{i}" /// }, - /// fun oce -> printfn $"Computation Cancelled: {i}")) - /// |> List.iter Async.Start + /// fun oce -> printfn $"Computation Cancelled: {i}") + /// |> Async.Start /// /// Thread.Sleep(6000) /// Async.CancelDefaultToken() @@ -235,13 +235,14 @@ namespace Microsoft.FSharp.Control /// /// /// - /// [ 2; 3; 5; 7; 11 ] - /// |> List.iter (fun i -> + /// let primes = [ 2; 3; 5; 7; 11 ] + /// for i in primes do /// async { /// use! holder = Async.OnCancel(fun () -> printfn $"Computation Cancelled: {i}") /// do! Async.Sleep(i * 1000) /// printfn $"{i}" - /// } |> Async.Start) + /// } + /// |> Async.Start /// /// Thread.Sleep(6000) /// Async.CancelDefaultToken() @@ -275,15 +276,17 @@ namespace Microsoft.FSharp.Control /// /// /// - /// try - /// let computations = - /// [ 2; 3; 5; 7; 11 ] - /// |> List.map (fun i -> + /// let primes = [ 2; 3; 5; 7; 11 ] + /// + /// let computations = + /// [ for i in primes do /// async { /// do! Async.Sleep(i * 1000) /// printfn $"{i}" - /// }) + /// } + /// ] /// + /// try /// let t = /// Async.Parallel(computations, 3) |> Async.StartAsTask /// @@ -307,13 +310,14 @@ namespace Microsoft.FSharp.Control /// /// /// Async.DefaultCancellationToken.Register(fun () -> printfn "Computation Cancelled") |> ignore - /// [ 2; 3; 5; 7; 11 ] - /// |> List.map (fun i -> + /// let primes = [ 2; 3; 5; 7; 11 ] + /// + /// for i in primes do /// async { /// do! Async.Sleep(i * 1000) /// printfn $"{i}" - /// }) - /// |> List.iter Async.Start + /// } + /// |> Async.Start /// /// Thread.Sleep(6000) /// Async.CancelDefaultToken() @@ -332,13 +336,13 @@ namespace Microsoft.FSharp.Control /// 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 - /// ... } + /// async { ... + /// 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 @@ -355,6 +359,7 @@ namespace Microsoft.FSharp.Control /// /// /// + /// /// let computeWithTimeout timeout = /// async { /// let! completor1 = @@ -402,19 +407,19 @@ namespace Microsoft.FSharp.Control /// /// /// + /// let primes = [ 2; 3; 5; 7; 10; 11 ] /// let t = - /// [ 2; 3; 5; 7; 10; 11 ] - /// |> List.map - /// (fun i -> - /// async { - /// do! Async.Sleep(System.Random().Next(1000, 2000)) + /// [ for i in primes do + /// async { + /// do! Async.Sleep(System.Random().Next(1000, 2000)) /// - /// if i % 2 > 0 then - /// printfn $"{i}" - /// return true - /// else - /// return false - /// }) + /// if i % 2 > 0 then + /// printfn $"{i}" + /// return true + /// else + /// return false + /// } + /// ] /// |> Async.Parallel /// |> Async.StartAsTask /// @@ -446,20 +451,19 @@ namespace Microsoft.FSharp.Control /// /// /// + /// let primes = [ 2; 3; 5; 7; 10; 11 ] /// let computations = - /// [ 2; 3; 5; 7; 10; 11 ] - /// |> List.map - /// (fun i -> - /// async { - /// do! Async.Sleep(System.Random().Next(1000, 2000)) + /// [ for i in primes do + /// async { + /// do! Async.Sleep(System.Random().Next(1000, 2000)) /// - /// return - /// if i % 2 > 0 then - /// printfn $"{i}" - /// true - /// else - /// false - /// }) + /// return + /// if i % 2 > 0 then + /// printfn $"{i}" + /// true + /// else + /// false + /// } ] /// /// let t = /// Async.Parallel(computations, maxDegreeOfParallelism=3) @@ -492,10 +496,9 @@ namespace Microsoft.FSharp.Control /// /// /// + /// let primes = [ 2; 3; 5; 7; 10; 11 ] /// let computations = - /// [ 2; 3; 5; 7; 10; 11 ] - /// |> List.map - /// (fun i -> + /// [ for i in primes do /// async { /// do! Async.Sleep(System.Random().Next(1000, 2000)) /// @@ -504,7 +507,8 @@ namespace Microsoft.FSharp.Control /// return true /// else /// return false - /// }) + /// } + /// ] /// /// let t = /// Async.Sequential(computations) @@ -539,13 +543,16 @@ namespace Microsoft.FSharp.Control /// /// /// printfn "Starting" - /// [ 2; 3; 5; 7 ] - /// |> List.map - /// (fun i -> + /// let primes = [ 2; 3; 5; 7 ] + /// let computations = + /// [ for i in primes do /// async { /// do! Async.Sleep(System.Random().Next(1000, 2000)) /// return if i % 2 > 0 then Some(i) else None - /// }) + /// } + /// ] + /// + /// computations /// |> Async.Choice /// |> Async.RunSynchronously /// |> function @@ -558,9 +565,9 @@ namespace Microsoft.FSharp.Control /// /// /// - /// [ 2; 3; 5; 7 ] - /// |> List.map - /// (fun i -> + /// let primes = [ 2; 3; 5; 7 ] + /// let computations = + /// [ for i in primes do /// async { /// do! Async.Sleep(System.Random().Next(1000, 2000)) /// @@ -569,7 +576,10 @@ namespace Microsoft.FSharp.Control /// Some(i) /// else /// failwith $"Even numbers not supported: {i}" - /// }) + /// } + //// ] + /// + /// computations /// |> Async.Choice /// |> Async.RunSynchronously /// |> function From 2afae7193bcd7e00d94327c4d09fa05555ce864e Mon Sep 17 00:00:00 2001 From: Don Syme Date: Fri, 23 Sep 2022 20:54:44 +0100 Subject: [PATCH 4/4] Update async.fsi --- src/FSharp.Core/async.fsi | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/FSharp.Core/async.fsi b/src/FSharp.Core/async.fsi index d88708015c1..3aa0403bb19 100644 --- a/src/FSharp.Core/async.fsi +++ b/src/FSharp.Core/async.fsi @@ -522,9 +522,11 @@ 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 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 @@ -532,7 +534,8 @@ namespace Microsoft.FSharp.Control /// /// 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 - /// for the other child computations to complete. + /// for the other child computations to complete. + /// /// /// A sequence of computations to be parallelized. /// @@ -577,7 +580,7 @@ namespace Microsoft.FSharp.Control /// else /// failwith $"Even numbers not supported: {i}" /// } - //// ] + /// ] /// /// computations /// |> Async.Choice