Rust: Dropping heavy things in another thread can make your code 10000x faster
111–120 of 285 posts
Re: Rust: Dropping heavy things in another thread can make your code 10000x faster
#112Just be careful, because moving heavy things to be dropped to another thread can change the semantics of the program. For instance, consider what happens if within that heavy thing you had a BufWriter: unless its buffer is empty, dropping it writes the buffer, so now your file is being written and closed in a random moment in the future, instead of being guaranteed to have been sent to the kernel and closed when the…
I only know a very little rust, but since it's generally a good practice to never defer writing (or other side effects) to an ambiguous future point in time - with memory allocations as the only plausible exception - is there any way in rust to make sure one doesn't accidentally move complex objects with drop side-effects into other threads? Granted the way the type system work you usually know the type of a variable…
If you're the one creating the structure, you could opt it out of Send, that'd make it… not sendable. So it wouldn't be able to cross thread-boundaries. For instance Rc is !Send, you simply can not send it across a thread-boundary (because it's a non-threadsafe reference-counting handle).
If you don't control the type, then you'd have to wrap it (newtype pattern) or remember to manually mem::drop it. The latter would obviously have no safety whatsoever, the former you might be able to lint for I guess, though even that is limited or complicated (because of type inference the problematic type might never get explicitly mentioned).
Re: Rust: Dropping heavy things in another thread can make your code 10000x faster
#113This is the standard problem with tracing data structures to free them. You frequently run into it with systems based on malloc/free or reference counting. The underlying problem is that freeing the structure takes time proportional to the number of pointers in the structure it has to chase. Generational/compacting GC has the opposite problem. Garbage collection takes time proportional to the live set, and the amount…
> This is the standard problem with tracing data structures to free them. You frequently run into it with systems based on malloc/free or reference counting. The underlying problem is that freeing the structure takes time proportional to the number of pointers in the structure it has to chase. That doesn't seem to make intuitive sense. A GC has the same problem. A garbage collector has to traverse the data structure…
Yes, but in practice tracing in a tracing GC is done concurrently and with the help of GC barriers that don't require synchronization and so are generally cheaper than the common mechanisms for reference-counting GC.
> and to invoke finalizers
As others have said, finalizers are very uncommon and, in fact, have been deprecated in Java.
Re: Rust: Dropping heavy things in another thread can make your code 10000x faster
#114Earlier quoted context omitted.
I think the contrived use case is just for illustrative purposes? If I'm understanding correctly, the combination of cleanup code and deallocation can sometimes consume enough time that it's worth dispatching it on another thread. That's hardly specific to Rust though. As you note that will certainly add some overhead, although that could be minimized by not spawning a fresh thread each time. It could easily reduce l…
It would be helpful to see an example from a real application, too.
Re: Rust: Dropping heavy things in another thread can make your code 10000x faster
#115I used to do this sometimes with C++ when I realized that clearing out a vector with lots of objects was slow. Is Rust basically based on unique_ptr? One problem with this approach was that you still had to wait for these threads when the application would shut down.
Rust is based on ownership and statically checked move semantics (by default though can be opted out). So each item has a single owner (which is why Rust deals very badly with graphs, and more generally any situation where ownership is unclear) and the compiler will prevent you from using a moved object (unlike C++).
Separately it has a smart pointer which is the dual of unique_ptr (Box), with the guarantee noted above:
let b = Box::new(1);
drop(b);
println!("{}", b);
will not compile because the second line moves the box, after which it can't be used because it's been removed entirely from this scope.Re: Rust: Dropping heavy things in another thread can make your code 10000x faster
#116Earlier quoted context omitted.
This code doesn't duplicate it. In Rust when a variable is sent as an argument to a function it's "ownership" moves to be in the scope of that function. https://doc.rust-lang.org/book/ch04-01-what-is-ownership.htm...
You're missing my point. Unless the only thing you want to do with your giant data structure is measure its size, you're not going to be passing ownership of your only copy of it into the get_size function. You're going to be passing in a copy -- hence the cost of duplicating everything.
Re: Rust: Dropping heavy things in another thread can make your code 10000x faster
#117Earlier quoted context omitted.
This deallocation trick is neat but in C and C++ you could use a memory pool to do this. In theory, you could also use a memory pool in Rust but I think the standard library uses malloc without some way of overriding this behaviour.
Yeah, I like Apple’s (Next’s) approach of pool allocation for each run through the event loop. Defer dealloc, drop pool at the end.
Re: Rust: Dropping heavy things in another thread can make your code 10000x faster
#118Earlier quoted context omitted.
This code doesn't duplicate it. In Rust when a variable is sent as an argument to a function it's "ownership" moves to be in the scope of that function. https://doc.rust-lang.org/book/ch04-01-what-is-ownership.htm...
You're missing my point. Unless the only thing you want to do with your giant data structure is measure its size, you're not going to be passing ownership of your only copy of it into the get_size function. You're going to be passing in a copy -- hence the cost of duplicating everything.
If it helps you, you might want to imagine the contents of the get_size function as being the end part of a longer calc_foo function. What's really missing the point is focusing so hard on the part that the example even contains a call to size() of a collection.
Re: Rust: Dropping heavy things in another thread can make your code 10000x faster
#119Earlier quoted context omitted.
How are finalizers invoked if the structure isn't traversed? Would it just be optimized away none of the objects have finalizers? Hence my suggestion about the area allocators being a better point of comparison.
Java is an example of a language with a generational copy collector by default. Most objects in Java don't have a finalizer, since after all the main point of, for example, destructors in C++ is to make sure you don't leak memory, which the GC solves. But when the `finalize` method is used is causes significant overhead. > Objects with finalizers (those that have a non-trivial finalize() method) have significant over…
Re: Rust: Dropping heavy things in another thread can make your code 10000x faster
#120Earlier quoted context omitted.
This deallocation trick is neat but in C and C++ you could use a memory pool to do this. In theory, you could also use a memory pool in Rust but I think the standard library uses malloc without some way of overriding this behaviour.
Yeah, I like Apple’s (Next’s) approach of pool allocation for each run through the event loop. Defer dealloc, drop pool at the end.