Earlier quoted context omitted.
Won't pre-emptible loops lead to more irreproducible race conditions as a negative consequence, unless the preemption is done deterministically?
Are you asking about BEAM or Go? Preemption already works in BEAM and doesn't lead to race conditions because of nothing shared concurrency.
Comparing Elixir and Go
191–200 of 202 posts
Re: Comparing Elixir and Go
#192Earlier quoted context omitted.
I was talking about Dialyzer when mentioning that but I wrote it that way because I didn't want to derail into an explanation of Dialyzer and how it works. I did link to a talk on it though. It's such an automatic part of the stack with no drawback to using it that it's why I wrote it that way. Check that talk though, it's really interesting.
Perhaps some quick parentheses--'(via Dialyzer)' would be enough. I'm familiar with Dialyzer but missed the reference in your post and thought wow, I didn't realize Elixir/Erlang had all this type checking built in... so definitely some potential for misunderstanding there. Overall excellent post though! Thanks for writing it.
Re: Comparing Elixir and Go
#193The article states that Elixir functions must be in a module, during its comparison between Goroutines and one of the few methods of using concurrency in Elixir (there are others beside spawn ). This description isn't entirely accurate. Named functions must be inside a module in Elixir, but anonymous functions don't have that requirement.
Re: Comparing Elixir and Go
#194I think the part about cooperative/preemptive multitasking isn't saying it all. Go multitasking is based on the compiler inserting switchpoints on function calls and syscall boundaries. But this affects the scheduling of a single OS-level threads executing that specific goroutine. The number of OS-level threads that the Go scheduler uses can arbitrarily grow, and OS-level threads are preemptively multitasked. So I th…
When you say "the number of threads that the Go scheduler uses can arbitrarily grow..." is it not set by GONUMPROCS or something like that? Or is it a dynamic thing -- new threads appear as needed? The cooperative issue is simply that until a thread does become free, the application can not respond to an event -- even given the epoll/kqueue architecture you describe.
* "G": these are goroutines
* "M": these are OS-level threads (the ones I was mentioning). These are bounded by debug.SetMaxThreads (default: 10000).
* "P": these are basically locks that Ms must acquire to run Go code. These are bounded by GOMAXPROCS.
So when you way "GOMAXPROCS=2", you're saying "I want at most two Gs executing code simultaneously", but you can still have a very high number of OS-level threads that are I/O blocked. Notice that when a G does a blocking I/O there are two possibilities: if it's a pollable operation, the handle is passed to the epoll/kqueue thread, the M releases its P and is recycled to do something else. If it's a non-pollable operation, the M releases the P but stays allocated to wait for the operation to finish (e.g.: the syscall to return). At that point, given that at least one P is free, any ready G can be scheduled, but a new M might be needed.
Re: Comparing Elixir and Go
#195Earlier quoted context omitted.
The performance issue still stands. Linked Lists are often MUCH slower then array backed lists on modern hardware. This is true even when doing lots of inserts. Having all your list in the CPU cache is just too much of a performance gain over having it spread out in random locations.
Depending on your GC, linked lists won't be "spread out in random locations." The nodes will be allocated right next to each other in the case where you're building up a list iteratively.
While I agree that this Linked list memory layout should be optimized, with real world tests Array backed normally win by a large margin.
Re: Comparing Elixir and Go
#196Earlier quoted context omitted.
Erlang is purely immutable and doesn't have any "facilities for mutation" that I know about, although it does have side effects (I/O, but no Haskell-style effect system).
That's not entirely true. I built a FlatBuffers implementation for Erlang as NIFs so that I could still take advantage of FlatBuffers memory efficiency features, which fundamentally required "unsafe" and mutable access to a byte buffer. I just had to be very aware of exactly how the runtime was going to interact with my implementation and account for it. Sadly the place where I worked was not keen on open source post…
Re: Comparing Elixir and Go
#197Author here. This was published a week earlier than expected so just a heads up that there are a couple of edits coming.
Great comparison. I'd love to see this expands to more languages. A quick question, you talk about Elixir yet mention Erlang a lot. Is the choice of Elixir over Erlang purely syntactic preferences? Or is Elixir just an all around win above Erlang?
In short: Elixir is more expressive and easier to write. There are a few syntax/stdlib peculiarities but frankly, every language has them. I'd only classify Go and Java as languages with slightly less WTFs in their stdlib compared to Elixir. I'd give 2-3% of Elixir's stdlib functions a slightly bad color. Perfectly acceptable IMO.
Erlang is probably just fine for people who are used to it but for me Elixir was much easier to pick up. Also it started gaining additional functionality which uses OTP's primitives. Check `GenStage` and `Flow` for higher level complex multi-process scenarios, they are really next-level stuff and they help a lot.
Re: Comparing Elixir and Go
#198I still don't understand what all the hype is about pure functional programming. Sometimes mutations are useful. There are lot of good programming design patterns which depend on mutations. Also, always copying objects by value every time you call a function seems very expensive; especially if you're dealing with very large objects/structs/maps/strings which have to be processed by many functions.
> Also, always copying objects by value every time
> you call a function seems very expensive
This is a non-point. In Erlang/Elixir everything is immutable and 95% of the time data is passed by an immutable reference thus effectively eliminating data copying.Also, if you use iolists for text processing (instead of appending strings), you absolutely will reuse all string chunks you use in the entire Erlang/Elixir OS process, even if you don't want to. It's mega-efficient.
EDIT: @josevalim (Elixir's creator) explains it much better than I can, right here in this thread: https://news.ycombinator.com/item?id=13499328.
Re: Comparing Elixir and Go
#199Earlier quoted context omitted.
You only need to copy the data if the consumer of the data changes it, i.e. copy-on-write.
That sounds a bit better than I thought but it still doesn't change the worst-case complexity.
The FP folk aren't close-minded about this. They just use mutability only when it's provably more performant than their builtin immutable data structures.
Re: Comparing Elixir and Go
#200I am very intrigued in both. I am a reasonably experienced software developer with about 15 hours a week of availability, anyone wants to contract me? I'd gain experience with a modern language, you'd get someone on cheaper than experience would suggest. I know software engineers can use any language but in reality, if I were to get a full time job at a company which uses either of these I'd get a lot less money than…