Why do we need to await? - asynchronous

The following piece of code is taken from the tokio crate tutorial
use tokio::io::{self, AsyncWriteExt};
use tokio::fs::File;
#[tokio::main]
async fn main() -> io::Result<()> {
let mut file = File::create("foo.txt").await?;
// Writes some prefix of the byte string, but not necessarily all of it.
let n = file.write(b"some bytes").await?;
println!("Wrote the first {} bytes of 'some bytes'.", n);
Ok(())
}
Why do we need to .await when creating a file?
let mut file = File::create("foo.txt").await?;
In other words, why do we need to create a file asynchronously? After all, we can't write to a file if it is not created yet, and hence it's enough simply to block on creating. If it creates successfully then write to it asynchronously, otherwise simply return an error. I definitely miss something.
UPDATE:
Please don't try to long-explain what asynchronous programming is, or what .await does. I know these topics very well. My question is: what is the reason in this example of creating a file asynchronously?

There is no practical reason to use .await in this simplistic example. One could argue this is a bad example, as it does not show any performance improvement over normal synchronous programming. However, a practical example of async is typically more complex, and the purpose of this example is to introduce the basic syntax.

Working with the file system is an asynchronous task. You are requesting to either write or read from the operating system which works independently of your program. your program can do other stuff while the file is loading. Await basically tells your program to stop execution of this function until the data requested is ready.

Related

How to make async function yield on block?

I just started learning asynchronous Rust, so this is propably not a difficult question to answer, however, I am scratching my head here.
I am not trying to run tasks in parallel yet, only trying to get them to run concurrently.
According to the guide at https://rust-lang.github.io/async-book/,
The futures::join macro makes it possible to wait for multiple different futures to complete while executing them all concurrently.
So when I create 2 Futures, I should be able to "await" both of them at once. It also states that
Whereas calling a blocking function in a synchronous method would block the whole thread, blocked Futures will yield control of the thread, allowing other Futures to run.
From what I understand here, if I await multiple Futures with join!, should the first one be blocked, the second one will start running.
So I made a very simple example where I created 2 async fns and tried to join! both, making sure the first one gets blocked. I used a mpsc::channel for the blocking, since the docs stated that thread::sleep() should not be used in async fns and that recv()
will always block the current thread if there is no data available
However, the behavior is not what I expected, as calling the blocking function will not yield control of the thread, allowing the other Future to run, like I would expect from the second quote I provided. Instead, it will just wait untill it is no longer blocked, finish the first Future and only then start the second. Pretty much as if they were synchronous and I would have just called one after the other.
My complete example code:
use std::{thread::{self}, sync::{mpsc::{self, Sender, Receiver}}, time::Duration};
use futures::{executor}; //added futures = "0.3" in cargo.toml dependencies
fn main(){
let fut = main_async();
executor::block_on(fut);
}
async fn main_async(){
let (sender, receiver) = mpsc::channel();
let thread_handle = std::thread::spawn(move || { //this thread is just here so the f1 function gets blocked by something and can later resume
wait_send_function(sender);
});
let f1 = f1(receiver);
let f2 = f2();
futures::join!(f1, f2);
thread_handle.join().unwrap();
}
fn wait_send_function(sender: Sender<i32>){
thread::sleep(Duration::from_millis(5000));
sender.send(1234).unwrap();
}
async fn f1(receiver: Receiver<i32>){
println!("starting f1");
let new_nmbr = receiver.recv().unwrap(); //I would expect f2 to start now, since this is blocking
println!("Received nmbr is: {}", new_nmbr);
}
async fn f2(){
println!("starting f2");
}
And the output is simply:
starting f1
Received nmbr is: 1234
starting f2
My question is what am I missing here, why does f2 only start after f1 is completed and what would I need to do to get the behavior I want (completing f2 first if f1 is blocked and then waiting for f1)?
Maybe the book is a little misleading, but when it refers to "a blocked future", it does not mean in the sense of blocking synchronous code (if that was the case, there would be no problem to use std::thread::sleep()), but rather, it means that the future is waiting to be polled by the executor.
Thus, std::mpsc that blocks the thread will not have the desired effect (definitely not on a single-threaded executor like future's, but it's a bad idea on multi-threaded executors too). Use futures::channel::mpsc and everything will work.

When compiling Rust to wasm (web assembly), how can I sleep for 10 milliseconds?

My rust program is managing memory for a 2d html canvas context, and I'm trying to hit ~60fps. I can calculate the delta between each frame easily, and it turns out to be roughly ~5ms.
I'm unclear on how to put my Rust webassembly program to sleep for the remaining 11ms. One option would be to have JavaScript call into Rust on every requestAnimationFrame and use that as the driver, but I'm curious to keep it all in Rust if possible.
I'm effectively looking for the Rust equivalent of JavaScript's setTimeout(renderNext, 11) when compiling out to the wasm target.
In your requestAnimationFrame callback, call setTimeout, and have that in turn make the next call to requestAnimationFrame. You can see the JS version of this here.
Based on the example in the wasm-bindgen book, here's how I do this in Rust:
fn animate_limited(mut draw_frame: impl FnMut() + 'static, max_fps: i32) {
// Based on:
// https://rustwasm.github.io/docs/wasm-bindgen/examples/request-animation-frame.html#srclibrs
// https://doc.rust-lang.org/book/ch15-05-interior-mutability.html
let animate_cb = Rc::new(RefCell::new(None));
let animate_cb2 = animate_cb.clone();
let timeout_cb = Rc::new(RefCell::new(None));
let timeout_cb2 = timeout_cb.clone();
let w = window();
*timeout_cb2.borrow_mut() = Some(Closure::wrap(Box::new(move || {
request_animation_frame(&w, animate_cb.borrow().as_ref().unwrap());
}) as Box<dyn FnMut()>));
let w2 = window();
*animate_cb2.borrow_mut() = Some(Closure::wrap(Box::new(move || {
draw_frame();
set_timeout(&w2, timeout_cb.borrow().as_ref().unwrap(), 1000 / max_fps);
}) as Box<dyn FnMut()>));
request_animation_frame(&window(), animate_cb2.borrow().as_ref().unwrap());
}
fn window() -> web_sys::Window {
web_sys::window().expect("no global `window` exists")
}
fn request_animation_frame(window: &web_sys::Window, f: &Closure<dyn FnMut()>) -> i32 {
window
.request_animation_frame(f.as_ref().unchecked_ref())
.expect("should register `requestAnimationFrame` OK")
}
fn set_timeout(window: &web_sys::Window, f: &Closure<dyn FnMut()>, timeout_ms: i32) -> i32 {
window
.set_timeout_with_callback_and_timeout_and_arguments_0(
f.as_ref().unchecked_ref(),
timeout_ms,
)
.expect("should register `setTimeout` OK")
}
Then you simply pass animate_limited a function to do your drawing (a closure like move || { /* drawing logic here */ } will do the trick), and the maximum framerate you want.
There are almost certainly improvements to be made, there. I'm very new to Rust and just spent far too long figuring out how to make this work. Hopefully this makes it quicker for someone else in the future.
I'm effectively looking for the Rust equivalent of JavaScript's setTimeout(renderNext, 11) when compiling out to the wasm target.
There are several Rust crates that have bindings to the JavaScript web API, most notably web-sys. Take a look at the documentation for one of the setTimeout overloads.
This is not really a Rust equivalent though, as it pretty directly calls the JS function. But you won't be able to get around that: sleeping or getting the current time are both functions that the host environment has to offer. They cannot be implemented in the raw language alone.
One option would be to have JavaScript call into Rust on every requestAnimationFrame and use that as the driver, but I'm curious to keep it all in Rust if possible.
Yes, you should use requestAnimationFrame (link to web-sys docs). This is much preferred over timing it yourself. In particular, this method will also pause calling your code when the tab is not active and stuff like that. In a desktop environment you would do the same: ask the host environment (i.e. the operating system, often via OpenGL or so) to synchronize your program to screen refreshes.

ASP.NET Core, overkilling Task.Run()?

Lets say we have an ASP.NET Core receiving a string as a payload, size order of couple of megabytes. First method implementation:
[HttpPost("updateinfos")]
public async Task UpdateInfos()
{
var len = (int)this.Request.ContentLength;
byte[] b = new byte[len];
await this.Request.Body.ReadAsync(b,0,len);
var content = Encoding.UTF8.GetString(b);
.....
}
Body is read with ReadAsync, this is good since we have I/O stuff on socket and having it asynchronous is for free due to the nature of the call itself. But if we have a look after, the GetString() method, is purely CPU, is blocking with linear complexity. Anyway this affect somehow the performance since other clients wait for my bytes to get converted in string. I think to avoid this the solution is to run GetString() on the thread pool, by this:
[HttpPost("updateinfos")]
public async Task UpdateInfos()
{
var len = (int)this.Request.ContentLength;
byte[] b = new byte[len];
await this.Request.Body.ReadAsync(b,0,len);
var content = await Task.Run(()=>ASCIIEncoding.UTF8.GetString(b));
.....
}
please don't mind the return right now, something more has to be done in the function.
So the question, is the second approach overkilling? If so, what is the boundary to discriminate what could be run as blocking and what has to be moved to another thread?
You are very much abusing Task.Run there. Task.Run is used to off-load work onto a different thread and asynchronously wait for it to complete. So every Task.Run call will cause thread context switches. Of course, that is usually a very bad idea to do for things that should not run on their own thread.
Things like ASCIIEncoding.UTF8.GetString(b) are really fast. The overhead involved in creating and managing a thread that encapsulates this is much larger than just executing this directly on the same thread.
You should generally use Task.Run only to off-load (primarily synchronous) work that can benefit from running on its own thread. Or in cases, where you have work that would take a bit longer but block the current execution.
In your example, that is simply not the case, so you should just call those methods synchronously.
If you really want to reduce the work for that code, you should look at how to work properly streams. What you do in your code is read the request body stream completely and only then you work on it (trying to translate into a string).
Instead of separating the process of reading the binary stream and then translating it into a string, you could just read the stream as a string directly using a StreamReader. That way, you can read the request body directly, even asynchronously. So depending on what you actually do with it afterwards, that may be a lot more efficient.

F# Async File Copy

To copy a file asynchronously, will something like this work?
let filecopyasync (source, target) =
let task = Task.Run((fun () ->File.Copy(source, target, true)))
// do other stuff
Async.AwaitIAsyncResult task
In particular, will this fire up a new thread to do the copy while I "do other stuff"?
UPDATE:
Found another solution:
let asyncFileCopy (source, target, overwrite) =
printfn "Copying %s to %s" source target
let fn = new Func<string * string * bool, unit>(File.Copy)
Async.FromBeginEnd((source, target, overwrite), fn.BeginInvoke, fn.EndInvoke)
let copyfile1 = asyncFileCopy("file1", "file2", true)
let copyfile2 = asyncFileCopy("file3", "file4", true)
[copyfile1; copyfile2] |> seq |> Async.Parallel |> Async.RunSynchronously |> ignore
Your question is conflating two issues, namely multithreading and asychrony. It's important to realise that these things are entirely different concepts:
Asychrony is about a workflow of tasks where we respond to the completion of those tasks independently of the main program flow.
Multithreading is an execution model, one which can be used to implement asychrony, although asychrony can be acheived in other ways (such as hardware interrupts).
Now, when it comes to I/O, the question you should not be asking is "Can I spin up another thread to do it for me?"
Why, you ask?
If you do some I/O in the main thread, you typically block the main thread waiting for results. If you evade this problem by creating a new thread, you haven't actually solved the issue, you've just moved it around. Now you've blocked either a new thread that you've created or a thread pool thread. Oh dear, same problem.
Threads are an expensive and valuable resources and shouldn't be squandered on waiting for blocking I/O to complete.
So, what is the real solution?
Well, we achieve asynchrony via one of these other approaches. That way, we can request that the OS perform some I/O and request that it let us know when the I/O operation is complete. That way, the thread is not blocked while we're waiting for results. In Windows, this is implemented via something called I/O completion ports.
How do I do this in F#?
The .NET CopyToAsync method is probably the easiest approach. Since this returns a plain task, it's helpful to create a helper method:
type Async with
static member AwaitPlainTask (task : Task) =
task.ContinueWith(ignore) |> Async.AwaitTask
Then
[<Literal>]
let DEFAULT_BUFFER_SIZE = 4096
let copyToAsync source dest =
async {
use sourceFile = new FileStream(source, FileMode.Open, FileAccess.Read, FileShare.Read, DEFAULT_BUFFER_SIZE, true);
use destFile = new FileStream(dest, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, DEFAULT_BUFFER_SIZE, true);
do! sourceFile.CopyToAsync(destFile) |> Async.AwaitPlainTask
}
You could then use this with Async.Parallel to perform multiple copies concurrently.
Note: This is different to what you wrote above because File.Copy is a sychronous method that returns unit while CopyToAsync is an async method that returns Task. You cannot magically make synchronous methods asychronous by putting async wrappers around them, instead you need to make sure you are using async all the way down.
You can test it yourself with a few printfns. I found I had to RunAsynchronously to force the main thread to wait for the copy to complete. I'm not sure why the await didn't work, but you can see the expected set of outputs indicating that the copy happened in the background.
open System
open System.IO
open System.Threading
open System.Threading.Tasks
let filecopyasync (source, target) =
let task = Task.Run((fun () ->
printfn "CopyThread: %d" Thread.CurrentThread.ManagedThreadId;
Thread.Sleep(10000);
File.Copy(source, target, true); printfn "copydone"))
printfn "mainThread: %d" Thread.CurrentThread.ManagedThreadId;
let result=Async.AwaitIAsyncResult task
Thread.Sleep(3000)
printfn "doing stuff"
Async.RunSynchronously result
printfn "done"
Output:
filecopyasync (#"foo.txt",#"bar.txt");;
mainThread: 1
CopyThread: 7
doing stuff
copydone
done
If all you're trying to do is run something on another thread while you do something else, then your initial Task.Run approach should be fine (note that you can get a Task<unit> if you call Task.Run<_> instead of the non-generic Task.Run, which might be marginally easier to deal with).
However, you should be clear about your goals - arguably a "proper" asynchronous file copy wouldn't require a separate .NET thread (which is a relatively heavy-weight primitive) and would rely on operating system features like completion ports instead; since System.IO.File doesn't provide a native CopyAsync method you'd need to write your own (see https://stackoverflow.com/a/35467471/82959 for a simple C# implementation that would be easy to transliterate).

How to change the dart-sqlite code from synchronous style to asynchronous?

I'm trying to use Dart with sqlite, with this project dart-sqlite.
But I found a problem: the API it provides is synchronous style. The code will be looked like:
// Iterating over a result set
var count = c.execute("SELECT * FROM posts LIMIT 10", callback: (row) {
print("${row.title}: ${row.body}");
});
print("Showing ${count} posts.");
With such code, I can't use Dart's future support, and the code will be blocking at sql operations.
I wonder how to change the code to asynchronous style? You can see it defines some native functions here: https://github.com/sam-mccall/dart-sqlite/blob/master/lib/sqlite.dart#L238
_prepare(db, query, statementObject) native 'PrepareStatement';
_reset(statement) native 'Reset';
_bind(statement, params) native 'Bind';
_column_info(statement) native 'ColumnInfo';
_step(statement) native 'Step';
_closeStatement(statement) native 'CloseStatement';
_new(path) native 'New';
_close(handle) native 'Close';
_version() native 'Version';
The native functions are mapped to some c++ functions here: https://github.com/sam-mccall/dart-sqlite/blob/master/src/dart_sqlite.cc
Is it possible to change to asynchronous? If possible, what shall I do?
If not possible, that I have to rewrite it, do I have to rewrite all of:
The dart file
The c++ wrapper file
The actual sqlite driver
UPDATE:
Thanks for #GregLowe's comment, Dart's Completer can convert callback style to future style, which can let me to use Dart's doSomething().then(...) instead of passing a callback function.
But after reading the source of dart-sqlite, I realized that, in the implementation of dart-sqlite, the callback is not event-based:
int execute([params = const [], bool callback(Row)]) {
_checkOpen();
_reset(_statement);
if (params.length > 0) _bind(_statement, params);
var result;
int count = 0;
var info = null;
while ((result = _step(_statement)) is! int) {
count++;
if (info == null) info = new _ResultInfo(_column_info(_statement));
if (callback != null && callback(new Row._internal(count - 1, info, result)) == true) {
result = count;
break;
}
}
// If update affected no rows, count == result == 0
return (count == 0) ? result : count;
}
Even if I use Completer, it won't increase the performance. I think I may have to rewrite the c++ code to make it event-based first.
You should be able to write a wrapper without touching the C++. Have a look at how to use the Completer class in dart:async. Basically you need to create a Completer, return Completer.future immediately, and then call Completer.complete(row) from the existing callback.
Re: update. Have you seen this article, specifically the bit about asynchronous extensions? i.e. If the C++ API is synchronous you can run it in a separate thread, and use messaging to communicate with it. This could be a way to do it.
The big problem you've got is that SQLite is an embedded database; in order to process your query and provide your results, it must do computation (and I/O) in your process. What's more, in order for its transaction handling system to work, it either needs its connection to be in the thread that created it, or for you to run in serialized mode (with a performance hit).
Because these are fairly hard constraints, your plan of switching things to an asynchronous operation mode is unlikely to go well except by using multiple threads. Since using multiple connections complicates things a lot (as you can't share some things between them, such as TEMP TABLEs) let's consider going for a single serialized connection; all activity will be serialized at the DB level, but for an application that doesn't use the DB a lot it will be OK. At the C++ level, you'd be talking about calling that execute from another thread and then sending messages back to the caller thread to indicate each row and the completion.
But you'll take a real hit when you do this; in particular, you're committing to only doing one query at a time, as the technique runs into significant problems with semantic effects when you start using two connections at once and the DB forces serialization on you with one connection.
It might be simpler to do the above by putting the synchronous-asynchronous coupling at the Dart level by managing the worker thread and inter-thread communication there. That would let you avoid having to change the C++ code significantly. I don't know Dart well enough to be able to give much advice there.
Myself, I'd just stick with synchronous connection processing so that I can make my application use multi-threaded mode more usefully. I'd be taking the hit with the semantics and giving each thread its own connection (possibly allocated lazily) so that overall speed was better, but I do come from a programming community that regards threads as relatively heavyweight resources, so make of that what you will. (Heavy threads can do things that reduce the number of locks they need that it makes no sense to try to do with light threads; it's about overhead management.)

Resources