Home
Contribute
Contact Us
Browse all meetings
Home
Contribute
Contact Us
Browse all meetings
Rust Programming Language
/
Rust and Tell Berlin
/ 8 Oct 2021
Rust Programming Language
/
Rust and Tell Berlin
/ 8 Oct 2021
Previous Meeting
Next Meeting
⏯
Sync
Add meeting
Rate page
Subscribe
►
From YouTube:
Rust & Tell Berlin September 2021 - Zeeshan Ali: Async/await: The good, bad and the ugly
Description
Details:
https://berline.rs/2021/09/22/rust-and-tell.html
A
(Closed captions, provided by prisma).
A
My name is zeeshan ali.
and yeah, I'll, be your first presenter.
A
bastian asked me if I can do a talk, last week,.
A
So I didn't get a lot of time to prepare this., and this is the first time I'm presenting this talk.
A
So I'm sorry if there is any mistakes.
A
and also,, I have to admit that I had to borrow.
A
A lot of things from tutorials and books and stuff.
A
So yeah.
A
First of all,, who am I?
like short introduction for those who still don't know, me.
A
I keep coming here so you should know me.
A
Anyway, I've been living in different countries,.
A
So I'm a bit of a nomad.
and I work for a company called mayadata..
A
I just started last month,, so don't ask me a lot of questions about what we do.
A
I'm still figuring that out., but what I know is that we provide highly, extremely efficient,, I wouldn't say high, but extremely efficient storage to the cloud,.
A
To kubernetes clusters, through a mega project called openebs.
A
And my job is to look at a specific project,.
A
A relatively new project in that space called mayastore.
A
So that's my job.
A
and I've been involved in the foss community.
A
For a long time, now.
A
and my background was with gnome and other,.
A
Mostly linux, embedded and desktop environment, develop.
A
I love planes and helicopters..
I had a helicopter license that I lost, because of slow, german bureaucracy,, but I do have a plane license that I got in germany..
A
So I'm more or less thankful for that.
A
And I love cats.
A
I'm also a member of async foundations, working group in rust.
A
I don't know how I became part of it,, but somehow I did,.
A
But I did contribute a bit,, not recently,, but for a while I did.
A
And so let's get into it.
A
like,.
What am I talking about?, first of all,?
What is it with async??
Why async?.
A
It's basically about concurrent programming.
A
and when I say concurrent programming,, first question that people would ask, why not just use threads?
and yeah,, you can use that.
A
and also rust, has,.
You know,.
A
Libraries, standard library for that.
A
So,, you can do that certainly., but it depends on your use.
Case, right?, the threads do have an overhead., so you have to ask yourself: like,?
Is your workloads there cpu-bound, or are they more I/o-bound?.
A
Because if they're I/o-bound,, you mostly spend time waiting.
A
And if you just want to wait,, you don't want lots of threads long just to wait,.
A
Because threads, as I said, have an overhead,, especially if you are on a low resource or a resource constraint in any way, environment, such as embedded systems,, then it's especially true.
A
And also like,, it gives you.
A
The look and feel of doing normal,, synchronous, programming.
A
So in here,, if you notice,, these are simple examples: also,.
A
But it's just the same.
A
As it would be, without async,, except that you're declaring the function, async,.
A
And when you call them,, you wait for them.
A
And that's the only two differences you will see: here.
A
But we will get into the detail of how this is working and stuff.
A
And then you say,, you wrote that code that I just showed.
A
And then you want to call that one of the functions.
A
And you do it like this, right?, or at least you would think so.
A
and then, if you write that code, it builds and it runs successfully,.
No warnings, whatsoever.
A
However,, it wouldn't print anything,, even though there were print statements, there.
A
So why on earth would it not print anything?
A
that doesn't make any sense, right?.
A
And if you look at the code,, the error that you will get from the compiler,.
A
It's not an error, sorry,, it's a warning.!
Sorry.
I said that you will not get a warning,, but I was wrong because that would be really bad.
A
If you didn't get a warning either., but at least you get a warning from rust.
A
so,, you get a warning that future is not used.
A
And what the hell is a future?, and what is this await?
and what is polling??
A
What does it even mean?, like this whole error, right?.
A
If you're new to it, that's what you will think., the main thing that you need to know first is.
A
Async functions,, they return in reality behind the scene,.
A
A future type, and future is a trait in rust.
A
It's a you know, how I always dream of seeing the future,.
A
So I wanted to show you the future.
A
and just like the dog,, you wouldn't actually like to see the future.
(chuckles).
When you see it,, it looks like this.
A
If you mainly focus on the type part,.
A
The associated type of output,, it's then becomes pretty simple to see.
It.
A
It's a type that you can ask for, an output, from.
A
It doesn't have any processing needed or whatever, to produce that output.
and you call,.
A
Basically, poll on it continuously, until it reels that output.
A
There's an enum poll in the standard library for that..
A
So if it's still can't produce that output,, it will say that it's pending., so a future has to stay.
it's either it's pending or it's completed..
When it's completed,, it's already,, you would call it.
A
You will get your output back.
A
What I just mentioned it's to suffice for now,.
A
But we will look into more later.
A
So, behind the scene,, when you de-sugar it,, like the compiler is,, you know, handing the async part for you., but it changes it into something like this..
A
It's actually a simple function, that you normally have,.
A
Not async,, but it returns something that implements the future trade that you just saw.
A
And the return type that you declared for your async becomes the output type of this future.
A
And these futures are inert., so that's why there was this warning.
A
That you are not using the future., you created the future,, so the async function that you called it gave you a future,, but you didn't wait for it,.
A
You didn't call it completion..
A
So that's why it didn't actually do anything..
A
You just got the output., so we need an entry-point to make news of this future that the async function is returning,.
Right?.
A
So that's await the future..
That's what the warning suggested, right?
A
like in a warning,, it said,.
You have to wait for it..
A
So let's do that..
So in the main function you call the same and then just add that await.
A
I want to wait for it., but computer says no,, because async is only allowed,.
A
That is the error.
You will get inside async functions and blocks..
A
So how do we handle this?.
A
Enter runtimes like you...
A
In rust, you have something called runtimes.
A
And it's not built-in to the standard library,.
A
It's not at least right now., and I don't think it will be.
A
and they're external.
A
for many reasons,.
It was thought that it should be kept external, and people can provide it with different solutions for it.
A
And there are multiple runtimes available out there,.
A
There's, you know, singlethreaded, multithreaded., a singlethreaded.
One is like,.
If you have a resource, as I mentioned, resource constraint, environment,, you don't want multiplethreads launching,, especially behind your back without you knowing..
A
So in those ones,, you will use a singlethreaded on times.
A
But if you don't care,, if you want things to be,.
A
Working as fast as they could be on your system,, then you would probably want to use the multithreaded runtime.
and it's typically much easier to use a multithreaded one,.
A
A singlethreaded has some constraint on it.
A
And the most common one are.
A
Tokio and async-std or async stead,, however, you pronounce it?
A
and for the purpose of this talk, I chose async-std,.
A
Because, frankly, just doesn't get enough advertisement.
A
As much as tokio does., so I thought I will give them some advertisement.
A
Although nothing against tokio,, I use tokio as well.
A
So yeah.
what we do,.
A
We use something called block on..
A
Actually, every runtime that I have seen provides disfunction.
A
With the same name,, with the same semantics and behavior.
A
So you use that block on and you give it a future.
A
And it synchronously keeps pulling it until it's complete,.
A
And it gives you the result., so that's how you will use it, for example.
A
And if you remember in the error, I showed it also talked about async blocks.
A
It wasn't just saying async functions., so what are async blocks??
A
You can actually create a future, anonymous future,, just on the fly,.
Just like you can create, functions and anonymous functions in rust.
A
You can also create anonymous futures just on the fly,.
A
And you can do it this way, for example.
A
and you can use it just like any other future.
A
But so far, what we have seen, you just keep waiting for things,.
So that's not really concurrency,.
A
If you are just waiting for each thing.
Separately, right?.
A
And one of the ways of achieving concurrency with async,.
A
Is spawning and tasks, warning tasks.
A
And actually, from what I know, also all of the runtimes that have seen,, they call it a task., so maybe there's a runtime that calls it differently.
A
So you have in tokio as well a task, and also in smol as well.
A
(indistinct), so you spawn it and it just takes future,.
A
And it just spawned for you.
A
in some runtimes,, you have to specifically detach it., so detach means like, just run it in the background,.
I don't care anymore.
A
But in async-std, it's the default, like if you you don't keep the return value of spawn,.
A
That task is then detached for you, automatically,.
A
Which is very useful, I think., so in here, it will just run those two and then you can just leave or do what other things, and those tasks are running.
In the background for you.
A
And when it completes,, it just goes away on its own.
A
But tasks themselves are also futures..
They implement the future trait,, which is really cool thing about rust,, like with the traits,.
A
You can add behavior to so many things.
A
Like your own types and stuff.
so, since future is implemented for task,.
A
You can use it as such,.
You can wait for it,.
You can do other things that we will see.
Later.
A
For example, combining futures, right?
A
so, for example,, there's a crate called futures,.
A
Which is actually maintained and written by rust developers.
A
And felt like it's under the rust lang, github space.
A
So it's quite officially,, it's almost like std,, but it's not std yet.
A
so, and a lot of these api.
A
That has existence at future's crate,.
A
It's planned to go into std at some point,.
A
I think all of it,, but I'm not sure about that,, but at least most of it will go at some point, into std in some shape., so anyway..
So it's more like a proving ground.
A
And there's one method: there called join,.
A
And you can join multiple,, it's actually a macro,, so you can give it many different futures at the same time,.
A
And it waits for them at the same time, like all of them.
A
And as soon as all of them are completed,, it returns.
A
So you can concurrently wait for tasks,, which is what you want when you're your task are I/o-bound.
A
As I said, most of the time, what you're doing is waiting for something to happen, waiting for data to be available and stuff..
A
So you just want to concurrently wait for events,.
A
And that's what you do: here.
A
And you have other goodies in futures crate, as well for futures,, like you can select on them.
Instead of joining them,, you can wait for either any of them.
Completing,.
A
So if you just want any of them, completing, that's what you would use, you would select on it.
A
or you can map them.
so,, as I said,.
Every future has an output,.
A
So if you want to modify the output some way and create a future out of it,, so you can just call .map and then a map, just like you do with the results and options and stuff.
A
And there's a concept called streams.
A
So, in future, you had, you know, one output.
A
You consume the future,, you pull it in a complete.
A
And you get output and that's the end of the story., but with streams, you can keep getting it.
A
You can keep getting output,.
A
Until it's depleted, for example.
A
And they're sort of like async version of iterators.
A
And actually,, when it will get.
A
Into std, the streams, most likely it will be renamed to async iterator,.
A
The stream type trait., so how do you use it?.
A
For a simple example,, you just,, you have some helpers in futures, script,.
A
That you can create futures out of some synchronous code and, as always, streams, also futures, but streams as well.
A
And in here we have something called repeat., you just give it some value and it just repeats it.
A
So this stream, each time you, you know,, call next on it,.
A
Just like you call next on iterator,, you call it on the stream,, but it async,, so you have to await it and it will, becomes,.
You know,.
A
It just keeps you in your values.
A
As I said, similar api to iterator,, there's a lot of helpers available in future, and other also provided by the runtimes,.
A
Different runtimes provide nice goodies.
A
But as I'm explaining async, and it's all cool and stuff,.
A
There's currently, some limitations as well.
A
And one of them is async traits are not possible.
A
by async traits.
I mean, traits with async functions.
A
And why is it not possible?, because a rust is supposed to be zero-costs,.
A
The main apis at least.- and this is not possible right- now.
A
It's not possible with the current rust implement,.
A
Rust,, you know, all the features of rust.: it's not possible to implement it, so that you can implement it with zero-cost.
A
You have to advocate to make async functions in traits possible.
A
But worry not,!
You have a nice trait called async-.
A
Nice crate called async trait.
and that you just use it like,.
A
Do I have an example: here?
yes!.
A
So you, you just,, you know, use it,.
A
It provides you with a macro,.
A
Attribute macro that you use it on your normal looking trait, and then,, you can just do async, fn.
A
and in the reality,.
In the background, it's doing allocation.
A
So as long as you're, okay with that cost,.
A
You can just use this and it's fine, and it works.
A
Similarly, for the same reasons, as far as I know,, you can't have async closures., so you have to do something a bit complex.
A
in here,.
You have a call that just takes a call back to call, is in callback, and just like, you will define a callback in a generic way,.
A
You tell it it's a function which doesn't take any input,, but it produces an output,, but the output is a future,.
A
And that future has to implement the future trait.
A
With the output that you need.
A
and that's how you'd use it.
and then we use it,, we call call, and we just pass it to async,.
A
Like, we pass it a call,, a call back,.
A
This creates an async flock, which implements future,, so you can use it like that.
A
And you have, one of the problems of having around times external.
A
To standard library is that,.
A
It's not really possible to write,.
A
Well, it's possible,, but with a lot of hard work., I know from my own experience, I've been implementing an async api for the last many months, that needs to be,, or I want it to be agnostic.
A
Of async runtimes out there.
A
and it's super difficult., there's a lot of problems that you need to solve.
A
To achieve that., it depends also,, like some simple things, are very much possible, like you can provide a diagnostic library,, but a bit more complex, where you have to read from sockets and transform what you read from sockets and stuff like that., then it's quite hard.
A
And also you have like some small problems that can become big problems.
If you encounter them.
A
And one is,, one of them is called async sandwich, sort of where you call async,.
A
You call...
(scoffs).
Basically, you call async from a synchronous from a async.
A
So you have a sandwich., so you decided to run a runtime.
A
And to run a future,, but in that future, down the line in the chain,, it's right here,, it's right directly under it.
A
But in reality, you would encounter this problem.
A
Where down the chain,, where you were calling a lot of functions, somewhere there,, you call a blocking function,, a asynchronous function,, and that uses block on to run some synchronous,.
A
Async work.
and then you have a problem,, because this can cause deadlocks,.
You can't run runtimes within runtimes.
A
and actually, if you do it with tokio, purely with tokio block on,, both inside and outside,,.
A
You will get a actual runtime error.
A
So that's a problem.
A
but rest assured the async working group,.
A
It knows all about all these issues,.
A
They have been informed and they are working on solutions,, proposing solutions to the greater rust community.
A
And also to std, maintainers and authors.
A
So yeah.
that was a very quick introduction to async..
A
So I'm sorry if I went very fast., but if there's any questions, I can answer.
A
(Audience applauds).
A
Yes?
[audience member], can you say a little bit more about- (audio error).
A
So one helper that you do have,.
A
It's a bunch of crates, written by someone called stefan.
A
He moved on from rust a while ago.
A
And he wrote this set-up file..
A
He actually wrote a very small runtime called smol,.
A
S-M-O-L.
and that was divided into really,, really small,.
A
Tiny sub-crates that have different functionality,, like async locks,.
If you need asynchronous new techs.
A
Or read-write lock or something like that., so you will use that crate.
and it only provides that,, right?
and async channels..
You want channels that are async.
Friendly, works very well with asynchronous code..
A
You use that., so those set of crates really help you out., but they go as not far enough, you know.
A
And also like, when he was going away,, he said,.
A
"Who wants to maintain my project?", so I volunteered, because I was depending on it so much.
A
So I'm one of the co-mantainers now, somehow.
A
And one of the things that wasn't there was async broadcast,.
A
Like there's async channels already,, but there was async broadcast, was missing., but he had a work and progress crate for that,.
A
So I picked that up with joshua's help, and we finished that and it's now published,.
A
And I maintained, I actually actively maintained that, because that's mostly my code, now.
A
Anyway,, so you have that as well, broadcast., so there's a lot of those kinds of crates.
A
and also like,.
If you're, okay, with it,.
A
Tokio does make it possible to use only subset of their crate,.
A
So if you just need, for example, as I mentioned, locks,.
A
You can just enable that,, you can disable all features,.
A
All the four features, and you just enable the channels feature, or locks.,.
A
And then you only have a crate that you're using, that only help that., so that helps., but there are some problems that are not solved in a way that is agnostic to async..
A
One of the ways that I did, like,- I needed someone to continue,.
A
Like, I had some tasks, internal in the crate.
A
That needed to be run, right?.
A
How do I do that without using a runtime?, and so I provided with this help of the smol data.
A
Async executer.
A
And I just run that inside,, but you have an option to run it yourself..
A
So if you want to integrate it with your runtime, very well,.
A
You can do that or you can do use the default,, which is, I launched a thread, and I just run it behind your back,.
A
But it's just one thread,, so it's not that bad.
A
So, but I had to bite the bullet and run this thread,, because there was no other choice.
A
Yeah.
sorry for a lot of details, I'm getting.
A
But we can talk later on.
B
[Assistant] another question?.
A
You had some.
B
[Audience member] yeah..
I wondered to know,.
B
How do you choose between the run times?
like,?
What is your criteria?
B
like,, which runtime to choose for?.
A
That's not as easy of question as you would think,.
A
Because people are very opinionated about it,.
A
Like, we in the async working group,.
A
We were talking about an example of a story,.
A
We came up with a story of someone wanting to move from tokio to async-std, for example.
A
and we came up with reasons,.
Why would they do that?.
A
But then the tokio guys came in like, "no,, that's not true,!
You can do this with tokio and do that." so, I'd said it's a bit...
A
Yeah.
but,, I would say that I vote,.
A
See which one works best for you., because there are different apis.
there's some apis for some use.
Cases,.
A
In async-std are much, much better to use and easier to use, for some use cases,.
A
But then the tokio ones are a lot better in terms of like,.
A
They're very generic,, so if you have generic problems, tokio, usually works.
A
But when you have some specific problems,, they might,.
A
That's my experience,.
I might be completely wrong,, but that's my experience,, that for specific use cases I think std usually, is the one that you go.
To.
A
[Assistant] anymore, questions?.
B
Could you speak into this thing, please?.
A
[Audience member]: are we a async, yet?
A
what?
(laughs) [audience member]?
Are we async yet?, not really yet.
(laughs)?
A
We are working on it.
A
[Assistant], can you pass it on to the next one, if there is one.
A
Don't be shy., I don't bite.
(chuckles).
B
[Assistant] no there's not..
Thank you!
So much.
(audience applauds).