Crust of Rust: Channels

  Рет қаралды 77,630

Jon Gjengset

Jon Gjengset

Күн бұрын

In this (fifth) Crust of Rust video, we cover multi-produce/single-consumer (mpsc) channels, by re-implementing some of the std::sync::mpsc types from the standard library. As part of that, we cover what channels are used for, how they work at a high level, different common channel variants, and common channel implementations. In the process, we go over some common Rust concurrency primitives like Mutex and Condvar.
This is a rich topic, and I highly recommend you go and try to read the crossbeam-channel or flume source code if you're hungry for more! Please also leave questions here or on Discord if you're confused, and I'll try to help explain what's going on.
You can find the final code at gist.github.com/jonhoo/935060... and the Discord at / discord
0:00:00 Introduction
0:08:20 Initial structure
0:14:27 Structure Q&A
0:19:20 send and recv
0:29:03 send/recv Q&A
0:34:36 Does it work?
0:40:28 Zero senders
0:46:27 Q&A
0:50:53 Why does it hang?
0:53:08 Implementation Q&A
0:58:37 Synchronous channels
1:05:55 Batch recv optimization
1:13:23 Channel flavors
1:18:48 Flavor Q&A
1:22:32 Other implementations
1:32:24 Future-aware channels
1:36:27 Where next?
1:38:24 Channels Q&A
You can find crossbeam-channel at github.com/crossbeam-rs/cross..., and flume at github.com/zesterer/flume/.
You can watch the live version with comments at • Crust of Rust: Channel...

Пікірлер: 82
@megumin4625
@megumin4625 Жыл бұрын
For anyone curious about `let _`, the two things about it are 1. It is a no-op (there's no assembly for it even; for the cases where there are, there's no difference between `let _ = stmt;` vs `stmt;`) 2. It allows you to ignore warnings (e.g. Result not used)
@jRsqILVOY
@jRsqILVOY 3 жыл бұрын
The use of mem::swap instead of allocating a new VecDeque was cool.
@chrisboyce5009
@chrisboyce5009 3 жыл бұрын
Thanks Jon, I really appreciate these videos. I've worked in a number of different programming domains over the years, and Rust has really challenged me to think about things differently. I've read the books and Rust by example, and while the definitions and examples always seem reasonable and make sense, it's been difficult for me to extrapolate that knowledge into the real world. I feel like it's been difficult for me to get an "intuitive" grasp on some of the core topics, so I appreciate that you explain _why_ you do certain things, and what some alternatives are. I seem to get more practical knowledge in the first 15 minutes of your videos than I have from days of my own research.
@jonhoo
@jonhoo 3 жыл бұрын
I'm so happy to hear that, thank you!
@simonfarre4907
@simonfarre4907 3 жыл бұрын
One of the best video resources regarding Rust. I thoroughly appreciate this.
@sivakrishna4270
@sivakrishna4270 Жыл бұрын
Thanks Jon, this series is proving to be really helpful along with those Q&A during the stream. Really appreciate your work!
@devajitasem4618
@devajitasem4618 3 жыл бұрын
Nom nom nom...
@EidosGaming
@EidosGaming 3 жыл бұрын
I absolutely love these Crust of Rust rediffusions. I'm watching them all, I'll definitely try to watch one live
@bjugdbjk
@bjugdbjk 2 жыл бұрын
Can u suggest with which 1 do we need to start !! imagine a guy with basics of rust .
@raiguard
@raiguard 2 жыл бұрын
@@bjugdbjk I'd recommend iterators first. They're super helpful to know. But mostly, start building real projects and come watch a crust of rust if you need help with that concept. I'm working on my first multithreaded project, so I read through the multithreading part of the rust book, then came here to watch Jon's explanation of channels.
@michaeleaster1815
@michaeleaster1815 3 жыл бұрын
Terrific video: thank you. I didn't think I'd watch the entire video, but it was quite interesting!
@jasonleo
@jasonleo 3 жыл бұрын
Haha, new intro
@xiuxiu624
@xiuxiu624 2 жыл бұрын
Damn I just found your channel - your videos have been extremely helpful. Thank you
@nicolaswolyniec1354
@nicolaswolyniec1354 5 ай бұрын
its been a few years since the release of this video, but It helped me a lot! thanks!
@Zizaco
@Zizaco 3 жыл бұрын
The video/stream was very helpful to understand channels. thanks
@dantenotavailable
@dantenotavailable 3 жыл бұрын
... ok i haven't watched the video yet but i just had to comment. Love the intro!
@darrennew8211
@darrennew8211 3 жыл бұрын
I'm pretty sure you want to signal the condition variable while you still hold the lock. Don't drop the lock guard before signalling the condition variable. (That's sort of how condition variables work in every language.) Otherwise, you can wind up not waking up due to race conditions, because two senders notify_one, and only one person wakes up. notify is (generally) implemented such that it wakes the waiter after you drop the lock, so you don't have to worry about someone waking up while the lock is still held. For people still confused, be aware that condvar is a concept decades old, with lots of questions answered online independent of Rust. Assigning to _ drops temporaries. But the tx variable is still holding onto the reference.
@jonhoo
@jonhoo 3 жыл бұрын
There seems to be "hot" debate on this topic. The man page for pthread_cond_broadcast has this to say: "The pthread_cond_broadcast() or pthread_cond_signal() functions may be called by a thread whether or not it currently owns the mutex that threads calling pthread_cond_wait() or pthread_cond_timedwait() have associated with the condition variable during their waits; however, if predictable scheduling behavior is required, then that mutex shall be locked by the thread calling pthread_cond_broadcast() or pthread_cond_signal()." This suggests that either way is fine. There are also posts out there suggesting that unlocking first measurably decreases contention: stackoverflow.com/questions/17101922/do-i-have-to-acquire-lock-before-calling-condition-variable-notify-one
@markday3145
@markday3145 3 жыл бұрын
Whoa. That “None if inner.senders == 0 =>” condition in the match looks weird. I’m going to have to go back and reread that section of The Book. That’s why I like these streams. I tend to learn new things that are incidental to the main topic.
@jonhoo
@jonhoo 3 жыл бұрын
That's one of my primary hopes with them - a sort of "learning by osmosis" by observing someone relatively experienced write "real" code :) Glad that it seems to be working!
@alvarozamora2679
@alvarozamora2679 2 жыл бұрын
@@jonhoo indeed it is!
@Blure
@Blure 3 жыл бұрын
Hello Jon, The Crust of Rust series has been incredibly handy thus far. Thanks! In other hand, and this is quite off topic but, what vim colorscheme are you using? It looks darker than base16-gruvbox-dark-hard.
@jonhoo
@jonhoo 3 жыл бұрын
Ah, that's just because of the compression the live stream is using. That'll hopefully be better in the next stream (or if you look at some older ones). It really is the dark hard version of gruvbox :)
@semigsedem
@semigsedem Жыл бұрын
I was stuck on only concidering recv() and try_recv() methods for both waiting until a 'send' and occasionally checking for R-user interrupts. You mentioned a implementation could have the reciever awoken by a sender or for any other signal such as a time out. And simple enough flume and mspc have the recv_timeout() method to do that all along.
@raptazure868
@raptazure868 3 жыл бұрын
Thanks a lot 😋
@efraimdeluxe
@efraimdeluxe 3 жыл бұрын
Nice Intro!
@fernandoherrera2769
@fernandoherrera2769 3 жыл бұрын
Hi Jon. Thanks a lot for these videos. They have been very helpful while learning Rust. I have been studying this code you wrote for channels and I was wondering what would be the best way to handle the error you get from locking the mutex. It seems everybody recommends to just unwrap it and let it panic. Is that the best we can do?
@jonhoo
@jonhoo 3 жыл бұрын
That's a good question! I suggest you go take a look at blog.rust-lang.org/2020/12/11/lock-poisoning-survey.html :)
@Mandragore12345
@Mandragore12345 2 жыл бұрын
In the video you didn't end up using strong_count from Arc, because you wouldn't know if the other clone of the Arc was a sender or a receiver. Wouldn't it be ok to notify_one anyway? If there is a receiver remaining all is ok. If there is no receiver remaining, there is no one waiting on the condvar, and thus nothing happens. Maybe it's because a call to notify_one is expensive? But then this would be a very rare event, and the trade off is a somewhat simplified implementation. Thanks for the videos!
@RuslanKovtun
@RuslanKovtun 2 жыл бұрын
54:40 most of the time you want any additional information available, similar to `Result` vs `-1`.
@cutyboi8630
@cutyboi8630 3 жыл бұрын
We need Ferris in intro too 😁
@advertslaxxor
@advertslaxxor 3 жыл бұрын
Sorry to hear you're moving to L.A. Best of luck, you will be missed :(
@jonhoo
@jonhoo 3 жыл бұрын
Why sorry? I'll still be making more videos from there!
@rnavarro50
@rnavarro50 3 жыл бұрын
Does a data structure that broadcasts every send to every receiver could be considered a "channel flavor" too? Or is this a totally different concept?
@aresli7058
@aresli7058 6 ай бұрын
Thanks Jon, but I have a question about condvar. At last, the condvar is not in the mutex, so I think multiple threads can call condvar.notify_one at the same time. Will that causes an race?
@DrOptix
@DrOptix 2 жыл бұрын
Hello, first of all this is a great channel. There are places for 10mins videos and there are places for > 1H videos. Now I'm in a place where I want to go deeper on some topics. Now, I guess you are on a linux flavor. What are you using to record the screen? Also are you using a wayland based shell. I try to use OBS on a KDE wayland shell and all I get is a beautiful black screen. Any tips would be great! Thank you!
@jonhoo
@jonhoo 2 жыл бұрын
Nope, this is good old X with OBS. I do want to try to move on over to Wayland soon though!
@foobargorch
@foobargorch 2 жыл бұрын
fwiw Go doesn't have unbounded channels, but that's trivially implementable using two rendezvous or bounded channels and a goroutine that buffers items between two branches of a select loop, that's equivalent.
@RitobanRoyChowdhury
@RitobanRoyChowdhury 3 жыл бұрын
Great Video!! But please setup Github Dark mode, there's a bunch of extensions for it, or even just a CSS file loaded with Stylo/Stylish would help immensely!
@jonhoo
@jonhoo 3 жыл бұрын
I actually personally don't like dark mode for web pages. I only have it set up for the docs on stream because I know some people watch the streams in dark rooms :) I very rarely go on GitHub during a stream, so don't think it's quite worth it to have an extension (that I'd also want to disable otherwise) just for the streams. I do try to warn in the rare cases where I'm about to switch to a bright screen though!
@_alyssarose
@_alyssarose 3 жыл бұрын
Is deduplicating the data for a double buffered stream feasible? PS Love your videos, they inspired me to start coding in Rust!
@jonhoo
@jonhoo 3 жыл бұрын
Well, there's no actual double buffering here. When I say it uses "twice the memory", it's really just that it has twice the reserved memory for the capacity of the VecDeques. It doesn't actually duplicate the sent data, like strings or vectors. So happy to hear that, thank you! :D
@_alyssarose
@_alyssarose 3 жыл бұрын
@@jonhoo okay I misunderstood then. So the while the memory footprint grows to accommodate the second VecDeque the data is still stored at most once and is just there to allow for the receiver to avoid locking if there's data in the second queue?
@jonhoo
@jonhoo 3 жыл бұрын
Exactly!
@anonymousnyancat3231
@anonymousnyancat3231 3 жыл бұрын
Are your dotfiles available? I love the Firefox theme and (poly?)bar. (also shell, neovim conf and whatnot ;))
@jonhoo
@jonhoo 3 жыл бұрын
They are! github.com/jonhoo/configs :)
@anonymousnyancat3231
@anonymousnyancat3231 3 жыл бұрын
@@jonhoo Thanks a ton! And also for all the wonderful Rust videos. You've really helped me learn a lot. (P.s. is there a way to suggest videos and not just vote on them? I'd love to see a clean Brainfuck interpreter written in Rust. (The existing implementations (that I found, at least) and my own are all a bit shabby with structure, so I'd love to see you create one.))
@jonhoo
@jonhoo 3 жыл бұрын
Thank you! There isn't a formal process, no; sending it my way as a suggestions is the best way 😅
@amaraojiji
@amaraojiji 2 жыл бұрын
I have a very odd request: can you use non-standard mouse pointer for your streams? Your pointer is exactly like default pointer in Cinnamon (and others DE), and it causes second pointer to be in the video, which is a bit confusing...
@Simon-xi8tb
@Simon-xi8tb 3 жыл бұрын
Channels are just meeting points between two threads. I have some experience with CSP via Clojure. Are semantics in Rust the same as in core.async ? Are things like alt, sliding buffers, dropping buffers implemented ?
@avjewe
@avjewe 2 жыл бұрын
What do you recommend for my usual use case : single sender (adding work units) multiple receivers (doing the work)?
@semigsedem
@semigsedem Жыл бұрын
Noob here, but a Arc might do the trick. T is a job, and any thread is free to push or pop jobs. Only idling threads are contending for the Mutex. For something both easy and elegant likely rayon is good starting point.
@stephenjames2951
@stephenjames2951 3 жыл бұрын
Should the Clone be protected by the mutex? Or does Arc protect itself.
@jaspervisser181
@jaspervisser181 3 жыл бұрын
What was the open discussion about _ will not drop the value, mentioned around 51:12?
@jonhoo
@jonhoo 3 жыл бұрын
Take a look at twitter.com/jonhoo/status/1292103918198104064 :)
@jaspervisser181
@jaspervisser181 3 жыл бұрын
@@jonhoo Thanks! Great video btw :)
4 ай бұрын
When there are no more senders (dropped) documentation says the receivers will return an Err.
@TheLANBeforeTime-uo9ph
@TheLANBeforeTime-uo9ph 2 ай бұрын
A side question for Nvim: on 24:04, Jon quickly duplicated the current paragraph/function, how did he do it?
@WatchingScience-gv8pe
@WatchingScience-gv8pe 18 күн бұрын
Probably visual inner paragraph yank -> vipy. Could also be yank inner paragraph with the flash setting on (that shows which section you've copied)
@TheLANBeforeTime-uo9ph
@TheLANBeforeTime-uo9ph 18 күн бұрын
The mysterious part is not the yank but the paste without the cursor moved. I think your answer couldn’t do it like so, can it?
@WatchingScience-gv8pe
@WatchingScience-gv8pe 18 күн бұрын
Both options should do it without moving the Cursor imho
@evanxg852000
@evanxg852000 3 жыл бұрын
0:32:55 But you said previously that the thread can be waken up by the os for no valid reason. In that case, are you still handled a LockGuard? lets say TA is holding the Convar lock while TB is waiting; and for some reason the OS wakes up TB while TA is not done. Can the OS let this happen? Is the Guard given back as Poisoned ? my concern is if the wait always return the Guard while not guaranteeing the other is done then there could be issues.
@jonhoo
@jonhoo 3 жыл бұрын
Ah, this is implemented internally in the Condvar in Rust. If it gets a spurious wake-up, and then fails to get the lock, it won't be able to produce a `LockGuard` to return, and therefore will instead go back to sleep.
@PandaNuker
@PandaNuker Жыл бұрын
doesn't the memswap optimisation invalidate the FIFO assumption?
@clubhi
@clubhi 3 жыл бұрын
Why is it that not taking a lock as many times means that it will be able to take locks faster. Is the os penalizing threads that change state frequently?
@jonhoo
@jonhoo 3 жыл бұрын
Every time the CPU tries to take a lock, it needs to coordinate with any other CPUs that are _also_ trying to take the lock, or at the very least with the CPU that previously held the lock. If CPUs are trying to acquire the lock less frequently, that means that there are both fewer cores to coordinate with, and it is more likely that _this_ CPU is the last one to have held the lock (and therefore coordination is unnecessary). If you're curious about what happens under the hood, I recommend reading about MESI: en.wikipedia.org/wiki/MESI_protocol
@BboyKeny
@BboyKeny Жыл бұрын
I needed to use channels to send a closure to JavaScript with wasm
@PaulSebastianM
@PaulSebastianM 3 жыл бұрын
Panama... Ouch! XD
@simonfarre4907
@simonfarre4907 3 жыл бұрын
Interesting that "let _ = ..." doesn't drop. That doesn't seem to be the case for _anything_ (even when it's scoped, which is even more weird) so I wonder what let _ = ... actually gets compiled to? However, if you would have scoped it, and named the variable, something like what I've written down below, it would have worked: #[test] fn close() { let (tx, rx) = channel::(); { let a = tx; } assert_eq!(rx.recv(), None); } So this is strange. So "let _ = ..." doesn't actually seem to do anything when just doing it to another variable.
@megumin4625
@megumin4625 Жыл бұрын
`let _` is a no-op. It gets compiled to nothing at all (no assembly). What it's good for is intentionally ignoring compiler warnings like `Result not used`.
@simonfarre4907
@simonfarre4907 Жыл бұрын
@@megumin4625 I can't remember where in the video this was in response to, but yeah it is a wild card, but it wasn't what my comment was about, if I remember correctly, I think it was about a compiler error given somewhere in the video. Ah yes, he tried to force a drop, by using "let _ = ..." but, right, assigning _ to a value is a no op, which can be a bit confusing, as this can have "different" behavior than if assigned to a return from a function. It is at 52:30
@megumin4625
@megumin4625 Жыл бұрын
@@simonfarre4907 I've tested this in godbolt, and `let _` does nothing to the assembly even in return. It drops in place if it was going to already, even without `let _`. I suspect this point might have gotten confused because people sometimes saw drops happening there, but without realizing it does it regardless (because it's a no-op in the first place). I saw a post explaining that `let _ = {i};` causes a drop, but `{i};` does the exact same thing in the assembly even (If anyone has an example to prove me wrong, I'd love to see it; I've been reading the assembly and cannot yet find that it's not a no-op)
@sheikhshakilakhtar6844
@sheikhshakilakhtar6844 3 жыл бұрын
Sorry, but I have two irrelevant questions which I would like you to answer. 1. Is your window manager i3? 2. Why are you using fish as opposed to bash/zsh?
@jonhoo
@jonhoo 3 жыл бұрын
Take a look at my video about my desktop setup over at kzbin.info/www/bejne/r5SwmoB6fdSjhMU :) These days, I use bspwm, not xmonad, as my window manager.
@sheikhshakilakhtar6844
@sheikhshakilakhtar6844 3 жыл бұрын
@@jonhoo Thanks a lot, Sir. One more question, if you do not mind. I am a beginner programmer learning C. Can you suggest projects/problems in C which can help me develop my programming skills in C?
@jonhoo
@jonhoo 3 жыл бұрын
I can't say I have much to recommend in the space of C education. I'd recommend you start with a different language, and then work your way up to C :) If you are intent on pursuing C, then I'd suggest starting with something like Project Euler, which has fairly well-defined and isolated exercises you can get started with.
@lucaspelegrino1
@lucaspelegrino1 3 жыл бұрын
What is "high contention" and "low contention"?
@jackmccarthy7644
@jackmccarthy7644 3 жыл бұрын
Contention refers to how often multiple threads are trying to access the same data. If a program has high contention, then lots of threads are trying to read/write to the same place at the same time, and will likely result in a lot of blocking, waiting, and fighting for mutex locks. Low contention means that there's usually only one thread trying to read/write at a time, so there will be much less blocking.
@TomasSandven
@TomasSandven 2 жыл бұрын
Can you fork and use channels to communicate between processes? If so, does T need to be Send?
@yourordinaryme
@yourordinaryme 3 жыл бұрын
AHHHH for the love of christ if you use Vim use find/replace or better yet a rename symbol plugin for changing names haha
@driziiD
@driziiD 3 жыл бұрын
mutex + condvar = monitor
@RoamingAdhocrat
@RoamingAdhocrat 11 ай бұрын
let inner = stuff; let inner = Arc::new(inner); is this idiomatic Rust, to create a variable and immediately replace it? can you not write: let inner = Arc::new(stuff); which I can see results in deeper nesting & therefore not great
Crust of Rust: Smart Pointers and Interior Mutability
2:03:04
Jon Gjengset
Рет қаралды 118 М.
Mojo Is FASTER Than Rust
19:22
ThePrimeTime
Рет қаралды 111 М.
ИРИНА КАЙРАТОВНА - АЙДАХАР (БЕКА) [MV]
02:51
ГОСТ ENTERTAINMENT
Рет қаралды 1,4 МЛН
Её Старший Брат Настоящий Джентельмен ❤️
00:18
Глеб Рандалайнен
Рет қаралды 8 МЛН
1❤️#thankyou #shorts
00:21
あみか部
Рет қаралды 84 МЛН
TRY NOT TO LAUGH 😂
00:56
Feinxy
Рет қаралды 13 МЛН
Crust of Rust: Sorting Algorithms
2:37:53
Jon Gjengset
Рет қаралды 59 М.
Crust of Rust: Atomics and Memory Ordering
2:39:20
Jon Gjengset
Рет қаралды 79 М.
Crust of Rust: Declarative Macros
1:36:11
Jon Gjengset
Рет қаралды 63 М.
Crust of Rust: Dispatch and Fat Pointers
2:12:52
Jon Gjengset
Рет қаралды 80 М.
Impl Trait aka Look ma’, no generics! by Jon Gjengset
1:09:05
Copenhagen Rust Community
Рет қаралды 26 М.
Rust for TypeScript devs : Borrow Checker
8:49
ThePrimeagen
Рет қаралды 213 М.
Solving distributed systems challenges in Rust
3:15:52
Jon Gjengset
Рет қаралды 178 М.
Message Passing With Rust MPSC Channels 🦀 Rust Tutorial
30:52
Trevor Sullivan
Рет қаралды 3,7 М.
Decrusting the axum crate
2:12:27
Jon Gjengset
Рет қаралды 63 М.
📦Он вам не медведь! Обзор FlyingBear S1
18:26
wireless switch without wires part 6
0:49
DailyTech
Рет қаралды 4 МЛН
5 НЕЛЕГАЛЬНЫХ гаджетов, за которые вас посадят
0:59
Кибер Андерсон
Рет қаралды 1,6 МЛН