Skip to content
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

[FS-1028] - Implement Async.StartImmediateAsTask #2534

Merged
merged 2 commits into from
Dec 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,102 @@ type AsyncType() =
Assert.IsTrue(t.IsCanceled)
Assert.IsTrue(!cancelled)

[<Test>]
member this.CreateImmediateAsTask () =
let s = "Hello tasks!"
let a = async { return s }
#if FSCORE_PORTABLE_NEW || coreclr
let t : Task<string> =
#else
use t : Task<string> =
#endif
Async.StartImmediateAsTask a
this.WaitASec t
Assert.IsTrue (t.IsCompleted)
Assert.AreEqual(s, t.Result)

[<Test>]
member this.StartImmediateAsTask () =
let s = "Hello tasks!"
let a = async { return s }
#if FSCORE_PORTABLE_NEW || coreclr
let t =
#else
use t =
#endif
Async.StartImmediateAsTask a
this.WaitASec t
Assert.IsTrue (t.IsCompleted)
Assert.AreEqual(s, t.Result)


[<Test>]
member this.ExceptionPropagatesToImmediateTask () =
let a = async {
do raise (Exception ())
}
#if FSCORE_PORTABLE_NEW || coreclr
let t =
#else
use t =
#endif
Async.StartImmediateAsTask a
let mutable exceptionThrown = false
try
this.WaitASec t
with
e -> exceptionThrown <- true
Assert.IsTrue (t.IsFaulted)
Assert.IsTrue(exceptionThrown)

[<Test>]
member this.CancellationPropagatesToImmediateTask () =
let a = async {
while true do ()
}
#if FSCORE_PORTABLE_NEW || coreclr
let t =
#else
use t =
#endif
Async.StartImmediateAsTask a
Async.CancelDefaultToken ()
let mutable exceptionThrown = false
try
this.WaitASec t
with e -> exceptionThrown <- true
Assert.IsTrue (exceptionThrown)
Assert.IsTrue(t.IsCanceled)

[<Test>]
member this.CancellationPropagatesToGroupImmediate () =
let ewh = new ManualResetEvent(false)
let cancelled = ref false
let a = async {
use! holder = Async.OnCancel (fun _ -> cancelled := true)
ewh.Set() |> Assert.IsTrue
while true do ()
}
let cts = new CancellationTokenSource()
let token = cts.Token
#if FSCORE_PORTABLE_NEW || coreclr
let t =
#else
use t =
#endif
Async.StartImmediateAsTask(a, cancellationToken=token)
// printfn "%A" t.Status
ewh.WaitOne() |> Assert.IsTrue
cts.Cancel()
// printfn "%A" t.Status
let mutable exceptionThrown = false
try
this.WaitASec t
with e -> exceptionThrown <- true
Assert.IsTrue (exceptionThrown)
Assert.IsTrue(t.IsCanceled)
Assert.IsTrue(!cancelled)


[<Test>]
member this.TaskAsyncValue () =
Expand Down
11 changes: 11 additions & 0 deletions src/fsharp/FSharp.Core/control.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1218,6 +1218,17 @@ namespace Microsoft.FSharp.Control
static member StartWithContinuations(computation:Async<'T>, continuation, exceptionContinuation, cancellationContinuation, ?cancellationToken) : unit =
Async.StartWithContinuationsUsingDispatchInfo(computation, continuation, (fun edi -> exceptionContinuation (edi.GetAssociatedSourceException())), cancellationContinuation, ?cancellationToken=cancellationToken)

static member StartImmediateAsTask (computation : Async<'T>, ?cancellationToken ) : Task<'T>=
let token = defaultArg cancellationToken defaultCancellationTokenSource.Token
let ts = new TaskCompletionSource<'T>()
let task = ts.Task
Async.StartWithContinuations(
computation,
(fun (k) -> ts.SetResult(k)),
(fun exn -> ts.SetException(exn)),
(fun _ -> ts.SetCanceled()),
token)
task
static member StartImmediate(computation:Async<unit>, ?cancellationToken) : unit =
let token = defaultArg cancellationToken defaultCancellationTokenSource.Token
CancellationTokenOps.StartWithContinuations(token, computation, id, (fun edi -> edi.ThrowAny()), ignore)
Expand Down
17 changes: 17 additions & 0 deletions src/fsharp/FSharp.Core/control.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,23 @@ namespace Microsoft.FSharp.Control
computation:Async<unit> * ?cancellationToken:CancellationToken-> unit


/// <summary>Runs an asynchronous computation, starting immediately on the current operating system,
/// but also returns the execution as <c>System.Threading.Tasks.Task</c>
/// </summary>
/// <remarks>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
/// async computation starts on the current thread with an ability to return a result.
/// </remarks>
/// <param name="computation">The asynchronous computation to execute.</param>
/// <param name="cancellationToken">The <c>CancellationToken</c> to associate with the computation.
/// The default is used if this parameter is not provided.</param>
/// <returns>A <c>System.Threading.Tasks.Task</c> that will be completed
/// in the corresponding state once the computation terminates (produces the result, throws exception or gets canceled)</returns>
/// </returns>
static member StartImmediateAsTask:
computation:Async<'T> * ?cancellationToken:CancellationToken-> Task<'T>



[<CompiledName("FSharpAsyncBuilder")>]
[<Sealed>]
Expand Down