crowded / ply Goto Github PK
View Code? Open in Web Editor NEWHigh performance System.Threading.(Value)Task computation expressions for F#
License: MIT License
High performance System.Threading.(Value)Task computation expressions for F#
License: MIT License
Hi, thanks for this great library!
I encountered the issue when I wanted to return early with return ()
, given user is actually null
, but the code actually continue to execute causing signInManager.PasswordSignInAsync
to throw null argument exception, how can I avoid this?
[<HttpPost("sign-in")>]
member _.SignIn(dto: SignInPortalParams) =
let username = dto.username
let password = dto.password
task {
let! user = userManager.FindByNameAsync(username)
if isNull user
then
logger.LogError $"Cannot find username {username}"
return ()
let! result = signInManager.PasswordSignInAsync(user, password, false, false)
if result.Succeeded
then
logger.LogInformation $"Sign in {user} successfully"
else
logger.LogError $"Sign in failed"
}
First of all - great job with dotnet/fsharp#2741 (comment)! It massively improves debugging experience. However, there's still at least one case when stack trace is lost: try...with
. To reuse your example:
module PlyProgram
open System.Threading.Tasks
open FSharp.Control.Tasks
open System
let findDingbobbleById(x: int) = vtask {
let! x = Task.Yield() // Force the Task to unwind the native stack
return invalidOp "Oh no"
}
let dingbobbleFeature() = vtask {
return! findDingbobbleById 1
}
let dingbobbleRoute() = vtask {
try
return! dingbobbleFeature()
with
| :? StackOverflowException as e -> return ()
}
[<EntryPoint>]
let main argv =
try dingbobbleRoute().GetAwaiter().GetResult() |> ignore
with ex -> Console.WriteLine(ex)
0
With stack trace:
System.InvalidOperationException: Oh no
at [email protected](Exception _arg2) in /home/abbradar/projects/somefun/src/Program.fs:line 21
at Ply.TplPrimitives.ContinuationStateMachine`1.System-Runtime-CompilerServices-IAsyncStateMachine-MoveNext()
at PlyProgram.main(String[] argv) in /home/abbradar/projects/somefun/src/Program.fs:line 26
Maybe we can improve this too?
EDIT: cleaned up the example
Are there any plans to support the new IAsyncDisposable?
Reposting @dsyme's question from TaskBuilder.
Hi all,
A question for people who use TaskBuilder, in relation to https://github.com/fsharp/fslang-design/blob/master/RFCs/FS-1097-task-builder.md
As everyone might know, the proposed support for tasks in F# is very much based around the functionality of TaskBuilder and we started with the test suite (though the implementation is entirely new).
Now TaskBuilder supports ContextInsensitive tasks where ConfigureAwait is false by default, e.g. https://github.com/rspeele/TaskBuilder.fs/blob/master/TaskBuilder.fs#L352. However the task { ... } support in the F# RFC doens't include ContextInsensitive tasks.
So the question is - how important is it for inbuilt F# task support to support a builder (e.g. open ContextInsensitive ... task { ...}) for context insensitive tasks? Or is it ok for people to do this manually?
Personally I think moving away from the UI thread should be done explicitly, e.g.
task {
do! Task.SwitchToBackgroundThread() // or whatever
... }
or via explicit ConfigureAwait calls.
While I'm not sure if I understand that correctly,
it would be nice to be able to launch tasks in parallel using and!
notation rather than launching them separately and then do! Task.WhenAll ...
i.e., instead of:
let task1 = launchTask1()
let task2 = launchTask2()
do! Task.WhenAll [| task1 :> Task; task2 :> Task |]
let! result1 = task1
let! result2 = task2
i'd prefer to write:
let! result1 = launchTask1()
and! result2 = launchTask2()
I've been moving some code from Taskbuilder.fs to Ply and I've noticed an odd compilation error.
It seems that when the type of an expression unwrapped with let!
is unspecified, it is always inferred as Ply<'t>
.
Naturally, if I'm not using the uply
builder, that's unlikely to be the default that I want, especially since it's an "unsafe" builder.
I'm much more likely to be composing the same kind of CE all the way through. But then I get a compile error at the call site because the let!
expects a Ply<_>
unless explicitly annotated.
Would it be possible to make each builder choose its own type as the default inference target for let!
and other unwrappings?
Minimal repro
open FSharp.Control.Tasks
let higherOrderTask t = task {
let! result = t()
return result + "_1"
}
let someTask () = System.IO.File.ReadAllTextAsync("/somePath")
let instance = higherOrderTask someTask
(* someTask: Type mismatch. Expecting a
'unit -> Ply.Ply<string>'
but given a
'unit -> Task<string>'
*)
Current workaround:
let! result = (t() : Task<_>)
Is there any equivalent of Async.Ignore
? It would be nice to have it.
Current:
task {
let! _ = ..
return ()
}
After:
task {
do! .. |> Task.ignore
}
F# newbie/learner here. Came across ply while following discussions about the performance of Async. Can we assume ply provides a referentially transparent representation of Tasks since it is based on computation expressions? If yes, it sounds like best of both worlds, performance and purity. Worth making this point in the introduction document.
I'd love to learn the answer to the question anyway. Many thanks for making this work open source. Looking forward to experimenting with it.
I didn't research what the root cause is, but in this example:
let testTask () =
task {
try
do! Task.Yield ()
failwith "Catch me"
with
| e ->
failwith "Fail now"
failwith "Test failed"
}
Current output is "Test failed". Ply 0.2.2.
read.me tells me to use the namespace FSharp.Control.Tasks.Builders
that is marked as obsolete in code and I'm told to use FSharp.Control.Tasks
.
And in release notes of FsToolkit.ErrorHandling: FSharp.Control.Tasks.NonAffine/Affine
Which namespace should be used?
Does Ply have the same performance issue with recursion as TaskBuilder.fs?
From TaskBuilder.fs documentation:
In F# it is idiomatic to use tail recursion to implement loops more complex than a simple for or while. works with some computation expressions (like the built-in F# async builder), but not with TaskBuilder.fs. As far as I know it is not possible to make this work with TPL tasks. C# async/await function are not tail-call optimized either, so at least this is consistent. implement a loop that may iterate many times (or indefinitely), use a while loop instead of tail recursion.
I'm seeing this error when calling a netstandard2.0 lib from a netcore2.2 app using the nuget package
System.MissingMethodException: Method not found: 'System.Threading.Tasks.Task`1<!!0> Ply.TplPrimitives.run(Microsoft.FSharp.Core.FSharpFunc`2<Microsoft.FSharp.Core.Unit,Ply.Ply`1<!!0>>)
However, it works if I import the source
I've been using Ply to great effect on an ultra-low-latency proof of concept, and it's been a joy to use. As of RFC FS-1072 native CE support for task creation is now an official part of F#, albeit on an experimental basis.
Do you believe that this will obsolete F#? Are there any benchmarks that compare Ply performance and the official F# support?
Nuget page has release notes link but RELEASE_NOTES.md does not exist.
Hello, I'd like to get a clarification on when to avoid unsafe builders with regards to the execution bubble.
It's rare that methods do anything with async locals or synchronization contexts, even in C#. So if you know anything you use doesn't do that either then there's nothing inherently unsafe about using the Unsafe CEs as you don't need any execution bubble for correctness.
What exactly does the bold part refer to? Use of synchronization contexts in my user code or also 3rd party library methods that I'm awaiting? For instance, given this code
let setupConnection () = unitVtask {
cmd.Connection <- new NpgsqlConnection (connectionString)
do! cmd.Connection.OpenAsync ()
do! cmd.PrepareAsync ()
if cfg.UseNetTopologySuite then cmd.Connection.TypeMapper.UseNetTopologySuite () |> ignore }
If I am unsure whether Npgsql uses synchronization contexts and want to play it safe, do I have to refrain from using unsafe builders all the way down? Or is it perfectly fine because OpenAsync
and PrepareAsync
return tasks with their own bubbles?
Additionally, I assume Unsafe.uply
is the most performant of the unsafe builders. Does it have any drawbacks compared to the rest of them when used internally in a library (i.e. it does not leak through the API)?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.