Let's say I have a synchronous expensive operation:
let SomeExpensiveOp():string=
System.Console.WriteLine"about to begin expensive OP"
System.Threading.Thread.Sleep(TimeSpan.FromSeconds 2.0)
System.Console.WriteLine"finished expensive OP"
"foo"
That I wrap as an async job:
let SomeExpensiveOpAs():Async<string>=async {
return SomeExpensiveOp()}
Now I want to use this expensive operation to combine it with other two:
let SomeExpensiveOpSeq():seq<Async<string>>=
let op = SomeExpensiveOpAs()
seq {
for some in [Bar(); Baz()] do
yield async {
let! prefix = op
let! someAfterWaiting = some
return (String.Concat (prefix, someAfterWaiting))
}
}
The purpose of putting it into a seq<Async<'T>> is to be able to use Async.Parallel this way:
let DoSomething() =
let someAsyncOps = SomeExpensiveOpSeq() |> List.ofSeq
let newOp = SomeExpensiveOpAs()
let moreAsyncOps = (newOp::someAsyncOps)
let allStrings = Async.RunSynchronously(Async.Parallel moreAsyncOps)
for str in allStrings do
Console.WriteLine str
Console.WriteLine()
However, this makes SomeExpensiveOp to be executed three times. I would expect the second time to be executed an extra time because of the newOp call above, but I was expecting SomeExpensiveOpSeq to reuse the call to SomeExpensiveOp instead of calling it twice. How can I achieve SomeExpensiveOpSeq to only call SomeExpensiveOp once and reuse that for subsequent results?
The key observation here is that let! is invoking the async expression every time—nothing caches its result. Consider this example where we have expOp : Async<string> but we await it three times in an async expression:
let expOp = SomeExpensiveOpAs()
async {
let! a = expOp
let! b = expOp
let! c = expOp
return [a;b;c]
} |> Async.RunSynchronously
about to begin expensive OP
finished expensive OP
about to begin expensive OP
finished expensive OP
about to begin expensive OP
finished expensive OP
val it : string list = ["foo"; "foo"; "foo"]
You can see the async expensive op gets evaluated each time. If you only want to execute that expensive operation once, you could fully evaluate/await its result and use that instead of awaiting it multiple times:
let SomeExpensiveOpSeq():seq<Async<string>>=
let op = SomeExpensiveOpAs() |> Async.RunSynchronously
seq {
for some in [Bar(); Baz()] do
yield async {
let! someAfterWaiting = some
return (String.Concat (op, someAfterWaiting))
}
}
This will still result in the expensive op being executed twice in your code—once in SomeExpensiveOpSeq and another as a result of being prepended on to moreAsyncOps—but it could be refactored further to a single invocation. Basically, if all subsequent async ops depend on this expensive evaluation, why not evaluate it once/first and then use its value wherever necessary:
let SomeExpensiveOpSeq op : seq<Async<string>>=
seq {
for some in [Bar(); Baz()] do
yield async {
let! someAfterWaiting = some
return (String.Concat (op, someAfterWaiting))
}
}
let DoSomething() =
let newOp = SomeExpensiveOpAs() |> Async.RunSynchronously
let someAsyncOps = SomeExpensiveOpSeq newOp |> Async.Parallel |> Async.RunSynchronously
let allStrings = newOp::(List.ofArray someAsyncOps)
for str in allStrings do
Console.WriteLine str
Console.WriteLine()
> DoSomething();;
about to begin expensive OP
finished expensive OP
foo
foobar
foobaz
Related
How do you create an async recursive function that takes a mutex? Rust claims that this code holds a mutex across an await point. However, the value is dropped before the .await.
#[async_recursion]
async fn f(mutex: &Arc<Mutex<u128>>) {
let mut unwrapped = mutex.lock().unwrap();
*unwrapped += 1;
let value = *unwrapped;
drop(unwrapped);
tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await;
if value < 100 {
f(mutex);
}
}
Error
future cannot be sent between threads safely
within `impl futures::Future<Output = ()>`, the trait `std::marker::Send` is not implemented for `std::sync::MutexGuard<'_, u128>`
required for the cast to the object type `dyn futures::Future<Output = ()> + std::marker::Send`rustc
lib.rs(251, 65): future is not `Send` as this value is used across an await
In this case, you can restructure the code to make it so unwrapped can't be used across an await:
let value = {
let mut unwrapped = mutex.lock().unwrap();
*unwrapped += 1;
*unwrapped
};
tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await;
if value < 100 {
f(mutex);
}
If you weren't able to do this, then you'd need to make it so you don't return a Future that implements Send. The async_recursion docs specify an option you can pass to the macro to disable the Send bound it adds:
#[async_recursion(?Send)]
async fn f(mutex: &Arc<Mutex<u128>>) {
...
(playground)
You wouldn't be able to send such a Future across threads though.
Lets assume we have the following C# method
public async Task DoStuffAsync(string path)
{
var fullPath = Path.Combine(
Directory.GetCurrentDirectory(),
path
);
using var stream = File.OpenText(fullPath);
while (!stream.EndOfStream)
{
var line = await stream.ReadLineAsync();
await Console.Out.WriteLineAsync(line);
}
}
and we want to implement this in F#, my first attempt was to code it like this
let doStuffAsync path =
async {
let fullPath = Path.Combine(Directory.GetCurrentDirectory(), path)
use stream = File.OpenText fullPath
while (not stream.EndOfStream) do
let! line = stream.ReadLineAsync() |> Async.AwaitTask
System.Console.Out.WriteLineAsync(line) |> Async.AwaitTask |> ignore
}
but that does not seam right to me as we have to unpack a Task<string> into a Async<string> then unpack this. Same for the Task from WriteLineAsync.
Are there no F# variantes for the methods ReadLineAsync and WriteLineAsync which return Async<_> instead of Task<_>?
Also is there somekind of async pipe operaor that would let me do
stream.ReadLineAsync()
|> Async.AwaitTask
|> System.Console.Out.WriteLineAsync
|> Async.AwaitTask
|> ignore
The use of Async.AwaitTask is correct as #NghiaBui pointed out. These are two async models and you need to convert in between them.
I'm afraid there are no Async<'T> variants of ReadlineAsync and most .net core libraries.
You could use TaskBuilder for some cleaner syntax:
task {
let fullPath = Path.Combine(Directory.GetCurrentDirectory(), path)
use stream = File.OpenText fullPath
while (not stream.EndOfStream) do
let! line = stream.ReadLineAsync()
do! System.Console.Out.WriteLineAsync line
}
Regarding the piping, I'm afraid it's not possible. There are some discussions to bring in a |>! operator but it looks like it would add more complexity than it's necessary.
I am attempting to create a list of strings which gets elements gradually inserted into asynchronously with the help of a mailbox processor. However I am not getting the desired output.
I have pretty much followed the code from https://fsharpforfunandprofit.com/posts/concurrency-actor-model/
however it does not seem to work as intended in my case. The code I have is as follows:
type TransactionQueue ={
queue : string list
} with
static member UpdateState (msg : string) (tq : TransactionQueue) =
{tq with queue = (msg :: tq.queue)}
static member Agent = MailboxProcessor.Start(fun inbox ->
let rec msgLoop (t : TransactionQueue) =
async{
let! msg = inbox.Receive()
let newT = TransactionQueue.UpdateState msg t
printfn "%A" newT
return! msgLoop newT
}
msgLoop {queue = []}
)
static member Add i = TransactionQueue.Agent.Post i
[<EntryPoint>]
let main argv =
// test in isolation
printfn "welcome to test"
let rec loop () =
let str = Console.ReadLine()
TransactionQueue.Add str
loop ()
loop ()
0
The result i keep getting is a list of the latest input only, the state is not kept. So if I enter "a" then "b" then "c" the queue will only have the value "c" instead of "a";"b";"c"
Any help or pointers would be most appreciated!
Just like C# Properties, your Agent is really a Property and thus behaves like a method with void parameter. That’s why you will get a new agent everytime Agent property is accessed.
In idiomatic F# there are two styles when implementing agents. If you don’t need to have many agent instances, just write a module and encapsule the agent-related stuff inside. Otherwise, OOP style should be used.
Code for style #1
module TransactionQueue =
type private Queue = Queue of string list
let private empty = Queue []
let private update item (Queue items) = Queue (item :: items)
let private agent = MailboxProcessor.Start <| fun inbox ->
let rec msgLoop queue = async {
let! msg = inbox.Receive ()
return! queue |> update msg |> msgLoop
}
msgLoop empty
let add item = agent.Post item
[<EntryPoint>]
let main argv =
// test in isolation
printfn "welcome to test"
let rec loop () =
let str = Console.ReadLine()
TransactionQueue.add str
loop ()
loop ()
Code for style #2
type Queue = Queue of string list with
static member Empty = Queue []
static member Update item (Queue items) =
Queue (item :: items)
type Agent () =
let agent = MailboxProcessor.Start <| fun inbox ->
let rec msgLoop queue = async {
let! msg = inbox.Receive ()
return! queue |> Queue.Update msg |> msgLoop
}
msgLoop Queue.Empty
member this.Add item = agent.Post item
[<EntryPoint>]
let main argv =
// test in isolation
printfn "welcome to test"
let agent = new Agent ()
let rec loop () =
let str = Console.ReadLine()
agent.Add str
loop ()
loop ()
Notice the use of Single-case union types for the Queue type.
I'm playing around with using SqlClient in F# and I'm having difficulty with using SqlDataReader.ReadAsync. I'm trying to do the F# equivalent of
while (await reader.ReadAsync) { ... }
What is the best way to do this in F#? Below is my full program. It works, but I'd like to know if there is a better way to do it.
open System
open System.Data.SqlClient
open System.Threading.Tasks
let connectionString = "Server=.;Integrated Security=SSPI"
module Async =
let AwaitVoidTask : (Task -> Async<unit>) =
Async.AwaitIAsyncResult >> Async.Ignore
// QUESTION: Is this idiomatic F#? Is there a more generally-used way of doing this?
let rec While (predicateFn : unit -> Async<bool>) (action : unit -> unit) : Async<unit> =
async {
let! b = predicateFn()
match b with
| true -> action(); do! While predicateFn action
| false -> ()
}
[<EntryPoint>]
let main argv =
let work = async {
// Open connection
use conn = new SqlConnection(connectionString)
do! conn.OpenAsync() |> Async.AwaitVoidTask
// Execute command
use cmd = conn.CreateCommand()
cmd.CommandText <- "select name from sys.databases"
let! reader = cmd.ExecuteReaderAsync() |> Async.AwaitTask
// Consume reader
// I want a convenient 'while' loop like this...
//while reader.ReadAsync() |> Async.AwaitTask do // Error: This expression was expected to have type bool but here has type Async<bool>
// reader.GetValue 0 |> string |> printfn "%s"
// Instead I used the 'Async.While' method that I defined above.
let ConsumeReader = Async.While (fun () -> reader.ReadAsync() |> Async.AwaitTask)
do! ConsumeReader (fun () -> reader.GetValue 0 |> string |> printfn "%s")
}
work |> Async.RunSynchronously
0 // return an integer exit code
There is one issue in your code which is that you're doing a recursive call using
do! While predicateFn action. This is a problem because it does not turn into a tail-call and so you could end up with memory leaks. The right way to do this is to use return! instead of do!.
Aside from that, your code works good. But you can actually extend the async computation builder to let you use ordinary while keyword. To do that, you need a slightly different version of While:
let rec While (predicateFn : unit -> Async<bool>) (action : Async<unit>) : Async<unit> =
async {
let! b = predicateFn()
if b then
do! action
return! While predicateFn action
}
type AsyncBuilder with
member x.While(cond, body) = Async.While cond body
Here, the body is also asynchronous and it is not a function. Then we add a While method to the computation builder (so we are adding another overload as an extension method). With this, you can actually write:
while Async.AwaitTask(reader.ReadAsync()) do // This is async!
do! Async.Sleep(1000) // The body is asynchronous too
reader.GetValue 0 |> string |> printfn "%s"
I'd probably do the same as you. If you can stomach refs though, you can shorten it to
let go = ref true
while !go do
let! more = reader.ReadAsync() |> Async.AwaitTask
go := more
reader.GetValue 0 |> string |> printfn "%s"
I wrote this little web listener simulation:
Agent.Start(fun (_ : MailboxProcessor<unit>) ->
let listener = new HttpListener()
listener.Prefixes.Add(addr)
listener.Start()
let rec respondOut() = async {
let! context = Async.FromBeginEnd(listener.BeginGetContext, listener.EndGetContext)
use s = context.Response.OutputStream
let wr = new StreamWriter(s)
use disp = { new IDisposable with
member x.Dispose() =
printfn "Disposing..."
wr.Dispose() }
wr.Write("Test")
return! respondOut()
}
respondOut()
)
I don't understand why Dispose is not called on disp on every loop?
As a side question, I'm doing all this because I want to test what is the proper behavior to respond text in a web service. I'm not sure if I should be doing:
use s = Context.Response.OutputStream
use sw = new StreamWriter(s)
sw.Write("test")
or
Context.Response.Write("Test")
Context.Response.End()
or whatnot.
Thanks!
When in doubt, use reflector :). The use keyword create the scope of "using" till then end of the block. When used inside the async workflow if you de-sugar the async keyword you will get something like:
Async.Bind(Async.FromBeginEnd(listener.BeginGetContext, listener.EndGetContext)
(fun context ->
use s = context.Response.OutputStream
let wr = new StreamWriter(s)
use disp = { new IDisposable with
member x.Dispose() =
printfn "Disposing..."
wr.Dispose() }
wr.Write("Test")
Async.ReturnFrom ( respondOut() )
)
Now the call Async.ReturnFrom at last will continue calling the function recursively and if you replace the use with " C# using() { } " where the } bracket is after the Async.ReturnFrom then the dispose will never get called
Wrapping the use part in a do block should solve the problem:
let rec respondOut() = async {
let! context = Async.FromBeginEnd(listener.BeginGetContext, listener.EndGetContext)
do
use s = context.Response.OutputStream
let wr = new StreamWriter(s)
use disp = { new IDisposable with
member x.Dispose() =
printfn "Disposing..."
wr.Dispose() }
wr.Write("Test")
return! respondOut()
}
use extends to the end of the block, so I would expect Dispose to be called after the recursive computation returns (which is never, in this case, since it loops unconditionally). If you want to dispose of the resource earlier, you'll need to delimit the scope of the use binding somehow. Perhaps something like this would work (I haven't tried it):
let rec respondOut() = async {
let! context = Async.FromBeginEnd(listener.BeginGetContext, listener.EndGetContext)
do! async {
use s = context.Response.OutputStream
let wr = new StreamWriter(s)
use disp = { new IDisposable with
member x.Dispose() =
printfn "Disposing..."
wr.Dispose() }
wr.Write("Test")
}
return! respondOut()
}
My guess is disp is optimized away in your compiled code since it isn't used. Try adding printfn "%A" disp on the next line.