Most active commenters
  • hintymad(3)
  • saagarjha(3)
  • surajrmal(3)

←back to thread

253 points chhum | 26 comments | | HN request time: 1.768s | source | bottom
Show context
exabrial ◴[] No.44006194[source]
Java performance isn't the fastest, that's ok, a close 3rd place behind C/CPP ain't bad. And you're still ahead of Go, and 10x or more ahead of Python and Ruby.

Java syntax isn't perfect, but it is consistent, and predictable. And hey, if you're using an Idea or Eclipse (and not notepad, atom, etc), it's just pressing control-space all day and you're fine.

Java memory management seems weird from a Unix Philosophy POV, till you understand whats happening. Again, not perfect, but a good tradeoff.

What do you get for all of these tradeoffs? Speed, memory safety. But with that you still still have dynamic invocation capabilities (making things like interception possible) and hotswap/live redefinition (things that C/CPP cannot do).

Perfect? No, but very practical for the real world use case.

replies(17): >>44006269 #>>44006358 #>>44006411 #>>44006567 #>>44006570 #>>44006865 #>>44007100 #>>44007464 #>>44007662 #>>44007666 #>>44009121 #>>44009861 #>>44011219 #>>44011642 #>>44012473 #>>44015715 #>>44016458 #
1. hintymad ◴[] No.44009121[source]
> And hey, if you're using an Idea or Eclipse (and not notepad, atom, etc),

Java's tools are really top notch. Using IntelliJ for Java feels a whole new different world from using IDEs for other languages.

Speaking of Go, does anyone know why Go community is not hot on developing containers for concurrent data structures? I see Mutex this and lock that scattering in Go code, while in Java community the #1 advice on writing concurrency code is to use Java's amazing containers. Sometimes, I do miss the java.util.concurrent and JCTools.

replies(4): >>44009525 #>>44009597 #>>44011488 #>>44014396 #
2. zwnow ◴[] No.44009525[source]
Just implement concurrency with actors and u save up on some locks and mutexes...

The patterns are available, its up to the community to apply proper concurrency patterns.

replies(3): >>44009714 #>>44009956 #>>44012415 #
3. eikenberry ◴[] No.44009597[source]
It's a core principle.

    Don't communicate by sharing memory; share memory by communicating.
The overuse of Mutex and Lock are from developers bringing along patterns from other language where they are used to communicating via shared memory. So this aspect of the language just doesn't click as well for many people at first. How long it takes you to get it depends on your experience.
replies(2): >>44009657 #>>44010054 #
4. hintymad ◴[] No.44009657[source]
Thanks! What about data structure shared by multiple goroutines? Say, an in-memory cache object? Or do we always have multiple goroutines talk to a dedicated goroutine for the shared value? Would the performance be okay for all use cases? A reason that people use JCTools is that it can easily support hundreds of millions of concurrent reads/writes to its data structures on a 10-year old laptop.
replies(1): >>44010784 #
5. paulddraper ◴[] No.44009714[source]
The x86 instruction set is available as well.
6. PaulDavisThe1st ◴[] No.44009956[source]
The only replacement for locks/mutexes is a lock free data structure. Locks are not what make concurrency possible, they are what makes it data-safe.

You can use platform threads, user-space threads, language-provided "green" threads, goroutines, continuations or whatever you wish for concurrency management, but that's almost orthogonal to data safety.

replies(1): >>44012944 #
7. fidotron ◴[] No.44010054[source]
My experience is a shocking amount of the golang community believe channels are a performance problem for whatever they're doing, and they use mutexes in some misguided effort at optimization.

But then I have also encountered Rust people that will look down on Java but had no idea buffered I/O had higher throughput than unbuffered.

replies(1): >>44014935 #
8. eikenberry ◴[] No.44010784{3}[source]
For things like cache I generally have 2 goroutines communicating with it. One that directs reads and one that directs writes. Using CSP style you can pass the data (by value) through to the cache (or any other CSP style process) without copying and it performs quite well. I've written several high performance systems in this way with great results.
9. shanemhansen ◴[] No.44011488[source]
I'll offer a counterpoint to the responses. Until go got generics, concurrent data structures were awkward. The stdlib now does include things like sync.Map.

In fact my experience has been that overuse of channels is a code smell that alot of new go developers fall into and later regret. There's a reason the log package uses a mutex for synchronization.

In general I think channels are great for connecting a few large chunks of your program together. Concurrency is great but also not every function call benefits from being turned into a distributed system.

I think that it would be a great idea to develop more concurrent go data structures with generics and I suspect inertia is what's keeping the community from doing it.

My credentials such as the are: been writing go since 1.0. worked at Google and taught go classes as well as owned some of the original go services (the downloads server aka payload server).

replies(2): >>44015310 #>>44020113 #
10. saagarjha ◴[] No.44012415[source]
Actors are implemented using locks.
replies(1): >>44012956 #
11. MaxBarraclough ◴[] No.44012944{3}[source]
I'm not sure what you mean here, as far as I'm aware data safety isn't standard terminology.
replies(1): >>44013655 #
12. pimeys ◴[] No.44012956{3}[source]
Is it really so? I haven't checked all the implementations, but my take here would be to use a channel with atomics instead of a lock...
replies(1): >>44013079 #
13. saagarjha ◴[] No.44013079{4}[source]
It's probably possible to do if you think about it carefully but generally enqueuing a message is going to take a lock, especially if you can send an arbitrary number of messages (which may require the queue to be reallocated).
replies(1): >>44013463 #
14. pimeys ◴[] No.44013463{5}[source]
One very common queue implementation you can use to implement actors is the crossbeam-deque. It's work-stealing in nature, works in multi-threaded environments and has no locks. The implementation is quite simple to follow:

https://github.com/crossbeam-rs/crossbeam/blob/master/crossb...

replies(3): >>44014986 #>>44019974 #>>44021874 #
15. lazide ◴[] No.44013655{4}[source]
I think they’re using it in the context of what you’ll get without some degree of locking, which is data corruption and/or other issues.

It’s not that you need locking to use threads. You need locking to stop threads from ruining any shared resource/data they are both trying to touch at the same time.

16. ◴[] No.44014396[source]
17. surajrmal ◴[] No.44014935{3}[source]
Depending on the situation, channels can absolutely be higher overhead and not worthwhile. Google internally recommends not using them in many situations.

Unbuffered IO is a tradeoff. For certain use cases it does help, because throughput isn't everything. I'm sure Buffered is better in the average use case, but that doesn't mean you would never need unbuffered.

replies(1): >>44015439 #
18. surajrmal ◴[] No.44014986{6}[source]
Note that the mpsc queue in the rust stdlib is also a clone of crossbeam and therefore also lockless.
19. hintymad ◴[] No.44015310[source]
Yeah, even with channels and goroutines, I’d imagine we can encapsulate them as primitives in containers like concurrency literatures often advocate. Case in point, it was fun to go through Pike’s talk Go Concurrency Patterns, yet I’m not sure all the patterns he discussed in the talk would be that simple to implement compared to just declaratively using well-packed containers
20. fidotron ◴[] No.44015439{4}[source]
> Depending on the situation, channels can absolutely be higher overhead and not worthwhile.

Like streaming arrays one byte at a time through the channel.

Such devs just aren't very good, and hear "Google internally recommends not using them in many situations" but jump to inferring that means all of their situations qualify.

> but that doesn't mean you would never need unbuffered.

Note that this was never claimed.

replies(1): >>44015979 #
21. surajrmal ◴[] No.44015979{5}[source]
Channels make the most sense when you need to decouple code. The performance differences rarely are a bit deal. Most of the time it's unnecessary cognitive overhead. People treat both sides as dogma, but the truth is that you need to be think critically when choosing between the two.
22. saagarjha ◴[] No.44019974{6}[source]
Oh, interesting. Ok I take back my claim then.
23. int_19h ◴[] No.44020113[source]
Not just generics, but also a way to generalize iteration (i.e. the equivalent of Java iterators). Which Go has only got even more recently than generics.
24. yubblegum ◴[] No.44021874{6}[source]
> One very common queue implementation you can use to implement actors is the crossbeam-deque

I can't find any references to a "crossbeam dequeue" outside of Rust sources. Is this a neologism for a "very common" pattern, or just very common in Rust?

replies(1): >>44022476 #
25. steveklabnik ◴[] No.44022476{7}[source]
crossbeam is a package name. It would be like googling “Nokogiri XML” and only getting Ruby results.

The generic name is just Deque. https://en.wikipedia.org/wiki/Double-ended_queue

replies(1): >>44022831 #
26. yubblegum ◴[] No.44022831{8}[source]
Thanks.