4 ms·
> To the point that I avoid using rust for web /networking stuff, any other option is better How can you write networking concurrent code in Golang then? It
by pkolaczk 4y ago
> To the point that I avoid using rust for web /networking stuff, any other option is better
How can you write networking concurrent code in Golang then? It doesn't support async traits either. Well, it doesn't support async at all, only green threads ;) And somehow people are ok with it, and say it is simple.
Hint: you can use the same style of concurrency in Rust. Don't use futures. Spawn frequently and communicate with channels.
- rastignack 4y agoAll the ecosystem is using Tokio and async for web stuff. I agree for those cases go is much saner.
- pkolaczk 4y agoMy point was that you can program in Rust in the exactly same style as Go, not hitting any of the problems mentioned in the linked article. Just use tokio::spawn and tokio channels and you get all the stuff you have in go. And btw, I just did that recently - I ported a proxy written in Go to Rust and actually it turned out to be simpler than the original thanks to things like join!, select!, RAII, being able to return a value from an async call easily.
- paskozdilar 4y agoIf you have any pieces of code you can share, I'd be interested in seeing what Go code looks like in equivalent Rust with tokio.
- paskozdilar 4y agoAsync/await is syntactic burden. In golang, everything is async so there is no need to differentiate between async/sync methods. Goroutines = coroutines with implicit await on every function call > And somehow people are ok with it, and say it is simple. Threads and queues are (IMHO) fairly easy to understand and work with. If you know how you'd write an application with threads and queues, goroutines and channels work pretty much the same way.
- pkolaczk 4y agoIt is not a syntactic burden, because it provides valuable information to the code reader. It is very important to me that I can quickly spot all places where execution can wait. For example, the user interface should take that into account, because noone likes programs that freeze temporarily waiting on something. Also, await points are places where execution can jump threads - this is critical to thread safety analysis. Making them invisible in a language that doesn't offer reliable data race detection is a similar idea like making types invisible in a language with dynamic and weak typing. And finally a model where await is implicit and automatically inserted by the compiler/runtime is less expressive (more limited) than async/await. For instance you wouldn't be able to do this if await was automatically inserted on each async thing, because they'd run sequentially and I don't want to: let future1 = do_one_async_thing(); let future2 = do_another_async_thing(); let (res1, res2) = join!(future1, future2); > Threads and queues are (IMHO) fairly easy to understand and work with 1. Sure, goto is easier to understand than for loops, ifs and functions. And it has its place, and I agree sometimes it can make things simpler. But I wouldn't want to work in a language where it is the only control flow construct. 2. Threads and queues are present in Rust as well, so that's not the reason Go could have an edge here.
- bheadmaster 4y ago> It is not a syntactic burden, because it provides valuable information to the code reader "Valuable" is subjective. I personally find async/await annotations annoying and pointless, and even leading to subtle bugs if you forget to put an "await" in the right place. Code should not depend on questions like "how long will this method run". > Making them invisible in a language that doesn't offer reliable data race detection is a similar idea like making types invisible in a language with dynamic and weak typing. Golang has a race detector: https://go.dev/blog/race-detector https://go.dev/blog/race-detector > For instance you wouldn't be able to do this if await was automatically inserted on each async thing, because they'd run sequentially and I don't want to You can do that in Golang with channels: ch1 := make(chan ResultType1) ch2 := make(chan ResultType2) go do_one_async_thing(ch1) go do_another_async_thing(ch2) res1 := <-ch1 res2 := <-ch2 To me, this approach is much more intuitive because communication happens explicitly through a channel, instead of implicitly through a Future that is magically returned from async functions if you don't put "await". > Sure, goto is easier to understand than for loops, ifs and functions. And it has its place, and I agree sometimes it can make things simpler. This is a dishonest take. Threads and queues are the most basic concurrent mechanisms, and async/await just emulates threads of execution in userspace. Golang does that too. The only difference is the lack of special syntax, and channels are used for inter-task communication instead of Futures. > Threads and queues are present in Rust as well, so that's not the reason Go could have an edge here. Threads in Rust are OS threads, and they are heavy. That's why the whole "async" world exists in the first place - because launching many OS threads slows down your system and takes up lot of memory. Go takes the execution model of threads, and emulates them in userspace with implicit async runtime, so they are much faster and take much less memory.