4 ms·
Using a plain-old mutex in Go isn't encouraged. As you said, the memory model is _share by communicating_. Sometimes, yes, using a mutex makes more sense -- an
by slimsag 12y ago
Using a plain-old mutex in Go isn't encouraged. As you said, the memory model is _share by communicating_.
Sometimes, yes, using a mutex makes more sense -- and that does introduce the possibility of a data race.
If you follow effective Go code -- I imagine the code is on average about just as safe as Rust code is. It is partially comparable to using `unsafe` blocks in Rust -- don't do it, unless you know what you're doing. Stick with channels.
- nothrabannosir 12y agoExample from personal experience: I'm working on an audio app right now, and I have high bandwidth, low latency data. I'm CPU bound, allocations and the GC are my enemy. It's just not feasible to constantly copy those buffers around. :( Don't take this the wrong way, I'm not complaining about Go. Just know that sometimes, there are real reasons to share memory. And when you do: Rust has got your back, but in Go you're on your own.
- giovannibajo1 12y agoNot sure what you mean; channels don't force you to copy buffers, you can simply pass the pointer/slice through the channel, but the point is that the paradigm encourages you to pass the ownership of that buffer through the channel.
- Animats 12y ago"the paradigm encourages you to pass the ownership of that buffer through the channel." Rust transfers ownership when you send a single-owner reference over a channel. The sender can no longer access the referenced object; the compiler prevents that. That's the safe way to do it. This is a significant advance in multi-thread programming. The rules that make this work are strikingly simple. Somebody should have thought of this 20 or 30 years ago, but as far as I know, nobody did. Rust pushes the single-owner model hard, and it seems to work. The C++ crowd beat their head against the wall on this for decades, through three generations of auto_ptr, then unique_ptr. Really getting it right requires something like the Rust borrow checker, which C++ does not have. Go does not do anything to prevent sharing data between threads. It's very easy in Go to unwittingly create shared data, because slices are references. After you've sent a reference, the sender still has access to the shared data, as does the receiver, so there's a potential race condition. Go does nothing to prevent this. There's a lot of dancing around this issue in "(In)effective Go", and long discussions of "is this a race condition" in Go forums. Go is a useful language, but it's in spite of Go's concurrency system, not because of it.
- rdtsc 12y agoNot sure there is a great advantage for that use case than from using C/C++ with threads and lockless queue of some sort.
- slimsag 12y agoWhy can't you transfer buffers as []byte or []float32 etc to another goroutine over a channel? Hint: that doesn't copy the buffer, it just transfers "ownership" of it.
- surrealize 12y agoWhat if the buffer is aliased? In rust, when you transfer ownership, you can statically guarantee that there's no aliasing. But AFAIK that's not possible in go.
- TheDong 12y ago"ownership" was in quotes because what he really means is "logical, but not language guaranteed, ownership". Both sides of the channel still can touch the underlying data and cause races.
- steveklabnik 12y agoWhile channels are awesome, and are a good pattern, what's important about Rust is that it lets you do channels, but if you need to share mutable memory for some reason, Rust still has your back in that use-case. We can guarantee no data races, even with shared mutable memory, at compile time. It's pretty huge. That said, channels in Rust are also nice to use, and you shouldn't not choose channels. Rust just enables other use-cases too.
- azth 12y ago> I imagine the code is on average about just as safe as Rust code is. The same claim can be made for C++ (with uniqe_ptr<T>), but we know how that faired. It is telling enough that there is a race detector tool for Go.
- Veedrac 12y agoNot really; Go is GC'd. C++ isn't memory safe.
- rdtsc 12y agoUsing unique_ptr correctly is memory safe. For example: std::unique_ptr<int> p(new int(1)); std::unique_ptr<int> q = p; Should fail. You can strong arm it into break but you can also reuse a pointer locally in Go after it was sent over a channel.
- Veedrac 12y agoC++ really isn't memory safe. It's trivial to think of an example: #include <iostream> auto f() { int x = 1; return [&] () { return x; }; } int main(int, char **) { std::cout << f()() << std::endl; } Of course "using <x> correctly" prevents bugs as long as - as C++ does - you define "correctly" as generously as possible. I agree Go isn't totally memory safe, but the level of memory safety is insanely less than in C++. If you want something particularly involving unique_ptr, consider that best practices are to give non-owning sharing as raw pointers: you could say they're safe as long as you use them correctly but again that misses the point. I can also give an example (stolen from a talk) directly involving shared_ptr even when used with traditional "best practices" although I'm sure the best practices will update themselves to include this. In some sense, Rust has been described as merely formalizing and automatically enforcing the best practices that people were already using in C++; it's the formality and automaticity that turns it from a dangerous language to a safe one.
- Rapzid 12y agoIt's not discouraged.. It's right there in the sync package. You can use channels where it makes sense, you can use RWMutex where it makes sense.