Live data from Hacker News

Tokio 1.0 – async runtime for Rust

tokio.rs

411–420 of 422 posts

Re: Tokio 1.0 – async runtime for Rust

#411

Earlier quoted context omitted.

That does answer my question, but I don't really understand why the distinction is made. To the caller, a function that spends time waiting and a function that spends the same time calculating both look the same, don't they?

The difference is that the runtime can schedule something else if the blocking is async. It looks the same as sync blocking to the caller, but not the scheduler. The point of async is you can write code that looks synchronous but is actually participating in cooperative multitasking.

I was expecting there to be more to it than that, but I understand their point now.

Re: Tokio 1.0 – async runtime for Rust

#412
post #406
post #397

Earlier quoted context omitted.

I like go, but i don’t understand your point. Go seems to like passing pointers over channels, which is pretty far from avoiding shared memory. Unless you start writing code that looks like actor based concurrency, with channels used to pass messages acrross actors. But this isn’t what i’d call idiomatic go.

> Unless you start writing code that looks like actor based concurrency, with channels used to pass messages acrross actors. But this isn’t what i’d call idiomatic go. Isn't that exactly what Go people push? "Don't communicate by sharing memory; share memory by communicating" and all that. If you start pushing pointers to shared memory around then I'd expect all of the problems of traditional multithreading to reappe…

Passing pointers to shared memory is highly unsafe in Go. While the Rust borrow checker will prevent all data races, there's nothing like that wrt. Go.

Re: Tokio 1.0 – async runtime for Rust

#413
post #378

Earlier quoted context omitted.

Cargo also has issues when two crates have incompatible dependencies, or at very least you end with the same crate being compiled a couple of times, as the hashes don't match up. Usually when compiling from source many libraries provide pkg-config configuration files on "make install".

Yes. Rust encourages version pinning. You go to "crates.io", and it gives you a specific version number to put in your "cargo.toml" file. Now you're nailed to that version for your program or crate. Crates have their own "cargo.toml" file, with their own versions, and it's quite possible to pull in multiple versions. Right now, I'm using the latest version of "reqwest" known to "crates.io." It's pulling in Tokio v0.2…

> Yes. Rust encourages version pinning.

Rust makes version pinning feasible, e.g. by allowing multiple versions of the same package in a build (not all module systems have this feature!) but doesn't encourage it. You've identified a problem with using 0.x.y-versioned packages as dependencies (which means de-facto opting out of semver), but that's not a problem with Rust specifically; it could occur in any language.

Re: Tokio 1.0 – async runtime for Rust

#414
post #211

Earlier quoted context omitted.

Or, you just take the initial leap and write async from the start. For languages with decent abstractions such as async/await, it really isn't hard when you've done it for a while, and I'd make the same argument as one of the parent posters in that it's great "documentation". K8s is brings way more complexity and headache, so it's kind of funny that you suggest that before using async/await.

> For languages with decent abstractions such as async/await, it really isn't hard when you've done it for a while https://lucumr.pocoo.org/2016/10/30/i-dont-understand-asynci...

I haven't used async in Python, but I'd bet you don't really _need_ to understand every single one of those concepts, unless you're developing something very niche and low level (or an interpreter). If you do need to know it, I'd argue that it's not a great abstraction; you definitely don't need to know that implementation details and concepts in either C# or Rust to use async/await.

Re: Tokio 1.0 – async runtime for Rust

#415
post #211

Earlier quoted context omitted.

Or, you just take the initial leap and write async from the start. For languages with decent abstractions such as async/await, it really isn't hard when you've done it for a while, and I'd make the same argument as one of the parent posters in that it's great "documentation". K8s is brings way more complexity and headache, so it's kind of funny that you suggest that before using async/await.

Setting up k8s once solves the problem for all your apps. In contrast, the additional software complexity of async/await is duplicated across all of them. If your planning to scale up, k8s is likely something you'll want later. Additional complexity in your apps is not.

> Additional complexity in your apps is not.

My point was that it really isn't that much additional complexity. 99.9% of the time, the main difference is that you'll have to write "await". You don't really need to know that there's a state machine hiding beneath.

Re: Tokio 1.0 – async runtime for Rust

#416

Earlier quoted context omitted.

Yes. Rust encourages version pinning. You go to "crates.io", and it gives you a specific version number to put in your "cargo.toml" file. Now you're nailed to that version for your program or crate. Crates have their own "cargo.toml" file, with their own versions, and it's quite possible to pull in multiple versions. Right now, I'm using the latest version of "reqwest" known to "crates.io." It's pulling in Tokio v0.2…

> Yes. Rust encourages version pinning. Rust makes version pinning feasible , e.g. by allowing multiple versions of the same package in a build (not all module systems have this feature!) but doesn't encourage it. You've identified a problem with using 0.x.y-versioned packages as dependencies (which means de-facto opting out of semver), but that's not a problem with Rust specifically; it could occur in any language.

To be clear, the default semantics are ^, not =. So even if you put 1.2.3 in your Cargo.toml, you may get 1.3.0, you just won’t get 2.0.0.

Re: Tokio 1.0 – async runtime for Rust

#417
post #406

Earlier quoted context omitted.

> Unless you start writing code that looks like actor based concurrency, with channels used to pass messages acrross actors. But this isn’t what i’d call idiomatic go. Isn't that exactly what Go people push? "Don't communicate by sharing memory; share memory by communicating" and all that. If you start pushing pointers to shared memory around then I'd expect all of the problems of traditional multithreading to reappe…

Passing pointers to shared memory is highly unsafe in Go. While the Rust borrow checker will prevent all data races, there's nothing like that wrt. Go.

> Passing pointers to shared memory is highly unsafe in Go. While the Rust borrow checker will prevent all data races, there's nothing like that wrt. Go

Passing pointers to shared memory is the foundation of a huge number of idiomatic, performant, and productive design patterns and architectures. There exist a number of conventions and tools, like the race detector, which reduce the risks of data races to entirely reasonable levels.

Re: Tokio 1.0 – async runtime for Rust

#418

Earlier quoted context omitted.

> Yes. Rust encourages version pinning. Rust makes version pinning feasible , e.g. by allowing multiple versions of the same package in a build (not all module systems have this feature!) but doesn't encourage it. You've identified a problem with using 0.x.y-versioned packages as dependencies (which means de-facto opting out of semver), but that's not a problem with Rust specifically; it could occur in any language.

To be clear, the default semantics are ^, not =. So even if you put 1.2.3 in your Cargo.toml, you may get 1.3.0, you just won’t get 2.0.0.

Which might lead to the same outcome anyway as there is nothing that prevents those version numbers to actually mean anything.

It is up to the library authors to uphold its semantics.

Re: Tokio 1.0 – async runtime for Rust

#419
post #337
post #77

I don't really get these modern async APIs. In languages like Javascript I thought they only made sense because JS interpreters are (historically) single-threaded, so you really have no choice but async to express some concepts. Fine. But in Rust you can just spawn threads, share data through channels or mutexes, use OS-provided async IO primitives to poll file descriptors and do event-driven programming etc... I tri…

I've not done nearly enough multithreaded programming, so this may be out of my depth, and what I'm saying and asking maybe completely wrong. Isn't async by design more efficient even when you have multiple threads you can spawn? My understanding is the event loop would do async tasks in the thread's quiet times, and put those tasks to sleep while it's waiting for io and other things, meaning the thread isn't blocked…

Yes! Programs can be much more efficient with non-blocking operations and a scheduler. This doesn't just benefit high performance web servers.

You gain some distinct advantages too by doing this, because you can then just run a single thread in your worker pool and if you ever need to make the program multi-threaded - god forbid - you can add locks to shared resources (or in Rust's case the compiler will help you with this) and then bump up the number of threads.

CPUs are really really fast today, I think engineers generally underestimate the amount of performance you can get with a single-thread and non-blocking I/O.

Async language constructs make this process a bit easier. The only issue IMO is that it is awkward to call async functions synchronously, or that it can have hidden costs to do so. I think languages will improve on this.

I believe on Linux, using non-blocking system calls on threads can help reduce expensive context switches too... whereas spawning multiple threads and having them use blocking system calls can cause more context switches.

I will say though.. I've seen developers just async-ify everything in codebases without thinking about why or if it is beneficial.

Re: Tokio 1.0 – async runtime for Rust

#420
post #403

Earlier quoted context omitted.

I think rust is kind of a perfect language for being profligate with dependencies, because the safety guarantees, typing, etc make it very hard to misuse a library, and relatively easy to design a library that is hard to misuse. A lot of what is not enjoyable about rust as a user is really nice when it's being imposed on people who are not you, whose work you're interfacing with.

Just because a library is safe does not make it good. To the point of the previous poster, you might for instance have an http library which does a lot of unnecessary async work behind the scenes to do a simple synchronous request. If we all have the attitude "it's good/fast because it's rust" this is not going to lead to a lot of cruft making its way into the ecosystem.

I think if a dependency is a perfectly sealed abstraction, where a complex function is reduced to a simple one with no leakage, then there's no reason not to use it.

Obviously, in the real world, this basically never happens. Performance is one thing that's basically always going to 'leak', so you still get people rewriting stuff in assembly, or making custom asics, because the abstractions that higher level languages offer are not perfect.

In a strongly typed language, with strong safety guarantees, I think there are less ways an abstraction can leak (for instance, by corrupting memory or whatever), so there's a correspondingly lower cost to pulling in a dependency than there would be if you were working in an unsafe language, or a dynamic one.

I also think if performance is the only way in which your dependency leaks implementation details, then it still makes sense to pull in a dependency first, profile, then swap out if necessary.

Post reply on HN