Live data from Hacker News

A deep dive into Multicore OCaml garbage collector

kcsrk.info

41–50 of 97 posts

Re: A deep dive into Multicore OCaml garbage collector

#41
post #2

OCaml has always intrigued me as something to learn, but it seems I always read equally as many reasons that it's not good, not ready, or why I should try Haskell instead. Does anyone have experience to say yay/nay on worthwhile learning, know of any companies using it heavily, or know of any large cleany written codebases from which to study?

From what I understand F# is a pretty close version of Ocaml, but has the benefit of all the libraries of the full .net ecosystem.

F# is basically an OCaml clone. I wonder why it isn't called NCaml or something like that. F# lacks some functional programming features the powerful macro system used for creating domain specific languages and extending the ocaml language.

Re: A deep dive into Multicore OCaml garbage collector

#42
post #19

I never managed to understand why so many people were apparently longering for multicore support. I just can't believe many are impatiently waiting for this feature to start using the ocaml language for some projects requiring multicore support, and I became impatient myself just to see what those projects are. In recent years where servers are to scale to many machines I found myself using less and less kennel threa…

In Go you can just do "go doWork()" and the scheduler runs the function as a coroutine on some kernel thread, thus allowing your program to make use of all cores.

The ability to just throw goroutines at the scheduler changes how you approach writing programs. For example, say you want to process an input that consists of lots of individual records. You can run the input stream in one goroutine, then spawn a bunch of worker goroutines that each receives records on a channel for processing. Since Go uses real threads and doesn't have a global lock, you can get nearly linear improvement in throughout here.

You wouldn't do this in, say, Ruby or Python, where the concurrency situation is about the same as in OCaml. Ruby has threads, like OCaml, but their slowness means they're not really usable in the same way as goroutines.

Parallelizing apps by forking child processes and communicating input and results via pipes is something I've done a lot in Ruby, and it's a really awkward, heavy-handed concurrency model.

Re: A deep dive into Multicore OCaml garbage collector

#43

Earlier quoted context omitted.

> or why I should try Haskell instead Haskell has some nice things going for it. Its syntax is cleaner than OCaml's, for example. Still, it makes some things (like having a mutable variable, or a hash table) much harder than they should be. It's worthwhile looking at both over some rainy weekends. Whichever you end up preferring, you'll have learned useful things about both languages. (OCaml is better, though ;-)) >…

> Haskell has some nice things going for it. Its syntax is cleaner than OCaml's, for example. While I find the ocaml syntax very far from perfect, the whitespace sensitivity of Haskell makes it immediately worse. What a silly design.

How does the whitespace sensitivity make it immediately worse?

Re: A deep dive into Multicore OCaml garbage collector

#44
post #19

I never managed to understand why so many people were apparently longering for multicore support. I just can't believe many are impatiently waiting for this feature to start using the ocaml language for some projects requiring multicore support, and I became impatient myself just to see what those projects are. In recent years where servers are to scale to many machines I found myself using less and less kennel threa…

Even if a particular application doesn't require any multicore support, usually at work I won't be working on just one application as part of a project, there'll be multiple applications involved, at least some of which will require shared memory parallelism. To me it doesn't make sense to pick a language that can only be used for a few applications not all, as this leads to unnecessary duplication in library code and the like compared to just using one language (in my case, C++) for all of them (similar to how people prefer to use the same language for frontend and backend to reduce duplication). Especially when the lack of multicore doesn't bring any compelling advantages: it saves a few percentage points of single-threaded performance at the expense of completely ruling out most use-cases that require shared memory parallelism (or at least rules out any ways of doing them that aren't incredibly un-ergonomic), which seems like an absolutely terrible trade-off to me.

Here's a concrete example: comparing the Isabelle proof assistant, written in PolyML (a multi-core supporting SML implementation developed mostly by one guy) with Coq (which is written in OCaml). Interactive theorem proving in the former is a lot nicer as it takes advantage of multithreading not only for faster concurrent processing of proofs, but also to do things like running Quickcheck and Nitpick in a separate thread automatically to identify trivially falsifiable lemmas, and automatically finding stdlib lemmas that exactly solve a particular proof.

I think PolyML demonstrates that a lack of manpower isn't what stopped OCaml implementing multithreading support. Over the years there have actually been a few proposals/branches implementing some form of support, but all were rejected/abandoned. There was even one that just made the runtime reentrant (passing the runtime around directly instead of having it as a global variable), meaning the OCaml runtime could now be stopped and restarted when embedded in another application (e.g. C calling OCaml), a feature already present in Haskell, but this relatively simple improvement was also rejected (which personally bothers me a lot on a subjective level as I hate globals so it seems like a worthy improvement for its own sake). I remember waiting excitedly four or five years ago for it to be merged, a small but significant step on the path to multicore support, only for that hope to fade away as contributions to the branch slowed to a trickle then dried up completely. Without such extreme focus on avoiding decreases in single-core performance, it would have been much easier for a change like this to have been merged.

I think in recent times there is even less justification for rejecting multicore for affecting single-threaded performance. For two reasons: firstly, the recent addition of FLambda has brought performance improvements in many cases of over 10%, easily enough to compensate for any loss from multi-threading. Secondly, HFT now basically requires FPGA to compete, so single-threaded performance would presumably be of less concern to Jane Street (OCaml's biggest industrial user) now as they really shouldn't be using a software execution engine anyway (disclaimer: I say that as someone working at a competing HFT firm). And if Jane Street isn't doing HFT, then a drop of a few percentage points in single-threaded performance shouldn't affect them much anyway.

Finally, OCaml could always do what Haskell did and add a flag to toggle whether or not multi-threading is enabled, allowing single-threaded users to avoid any performance regression.

Re: A deep dive into Multicore OCaml garbage collector

#45
post #19

I never managed to understand why so many people were apparently longering for multicore support. I just can't believe many are impatiently waiting for this feature to start using the ocaml language for some projects requiring multicore support, and I became impatient myself just to see what those projects are. In recent years where servers are to scale to many machines I found myself using less and less kennel threa…

In Go you can just do "go doWork()" and the scheduler runs the function as a coroutine on some kernel thread, thus allowing your program to make use of all cores. The ability to just throw goroutines at the scheduler changes how you approach writing programs. For example, say you want to process an input that consists of lots of individual records. You can run the input stream in one goroutine, then spawn a bunch of…

I whole heartedly agree with you on the convenience of go routines. I haven't been following the ocaml concurrency sorry; are they implementing a similar concurrency model?

Re: A deep dive into Multicore OCaml garbage collector

#46

Earlier quoted context omitted.

> Haskell has some nice things going for it. Its syntax is cleaner than OCaml's, for example. While I find the ocaml syntax very far from perfect, the whitespace sensitivity of Haskell makes it immediately worse. What a silly design.

IMHO, it's not so much that as the ASCII operator galore. $, , the horrible lambda syntax... Sometimes it looks an opinionated Perl.

I don't know if you've worked with a production Haskell code base but it cannot be over stated what a poor decision operator overloading is. if they got rid of that it would immediately make Haskell an order of magnitude more practical

Re: A deep dive into Multicore OCaml garbage collector

#47
post #19

I never managed to understand why so many people were apparently longering for multicore support. I just can't believe many are impatiently waiting for this feature to start using the ocaml language for some projects requiring multicore support, and I became impatient myself just to see what those projects are. In recent years where servers are to scale to many machines I found myself using less and less kennel threa…

In Go you can just do "go doWork()" and the scheduler runs the function as a coroutine on some kernel thread, thus allowing your program to make use of all cores. The ability to just throw goroutines at the scheduler changes how you approach writing programs. For example, say you want to process an input that consists of lots of individual records. You can run the input stream in one goroutine, then spawn a bunch of…

In OCaml there is Lwt. It provides very light-weight cooperative threads. The context switches are very fast and composing cooperative threads allows the writing of highly asynchronous applications. For instance, in the versions of Go prior to 1.5 goroutines used to run on a single core. And as of 1.5 the variable GOMAXPROCS can be set to the number of cores. EDIT:clarify the difference between concurrency and parallelism.

Re: A deep dive into Multicore OCaml garbage collector

#48
post #45

Earlier quoted context omitted.

In Go you can just do "go doWork()" and the scheduler runs the function as a coroutine on some kernel thread, thus allowing your program to make use of all cores. The ability to just throw goroutines at the scheduler changes how you approach writing programs. For example, say you want to process an input that consists of lots of individual records. You can run the input stream in one goroutine, then spawn a bunch of…

I whole heartedly agree with you on the convenience of go routines. I haven't been following the ocaml concurrency sorry; are they implementing a similar concurrency model?

Multicore OCaml comes with native support for concurrency through algebraic effect handlers which generalize common control flow abstractions such as exceptions, async/await, generators, non-determinism, backtracking. All of these mechanisms can be implemented directly in OCaml. [0] introduces the model, [1,2] has examples, and for further reading see [3].

[0]: http://kcsrk.info/ocaml/multicore/2015/05/20/effects-multico...

[1]: http://kcsrk.info/ocaml/multicore/effects/2015/05/27/more-ef...

[2]: https://github.com/kayceesrk/effects-examples

[3]: See recent pubs here http://kcsrk.info/.

Re: A deep dive into Multicore OCaml garbage collector

#49

Earlier quoted context omitted.

OCaml has many of the good qualities people attribute to Go (simplicity, speed, relatively low-latency GC, well-engineered compiler&runtime) and none of the downsides. Its weakness is terrible support for multithreading (like CPython it has a global lock, such that only one thread can execute OCaml code at a time), but there's work in progress to fix that. Personally I'm of the opinion that if the developers had take…

People often don't like the syntax too much (which is why Facebook invented Reason). There are other weaknesses as well: - the stdlib is good for data structures and not much else, which in turn gave rise to at least three different stdlib extensions - it does not have typeclasses, so implementing a generic "to_string" for your data type is not a thing - it has some really unfortunate ideas like "universal compare" -…

The community tends to shy away from classes, but using a method for to_string accomplishes your second point in a minimal way.

  let to_string stringer : string = stringer#to_string
  val to_string :  -> string = 

I think there's also plenty of people who feel just as strongly about Reason syntax in the other direction.

Re: A deep dive into Multicore OCaml garbage collector

#50
post #15

Earlier quoted context omitted.

> you can cheat a little and write imperative code if you really need to I'm not sure if this is cheating. Yes, this can be misused to introduce side-effects where there should be none. However, the strict evaluation by default (and lazy evaluation only when explicitly marked) has a huge benefit that you can not only reason easily about correctness (as in Haskell), but also reason easily about performance. The latter…

> Having said that, reasoning about performance is even better in Rust, which is heavily inspired by OCaml but allows to to reason about memory access, closing the gap that you can reason about OCaml's performance only while ignoring the GC. Rust is a really different topic. It's an imperative low-level language with functional trappings, not the reverse. First off, "reasoning about memory access" really means "think…

Idiomatic rust avoids heap allocations, but it very much encourages immutable stack allocation...something that OCaml also tries to encourage.

Rust started out a lot like OCaml, and gradually moved away from it whenever they needed to make a compromise to improve its position as a systems language. You start to see it with big things like how the pattern matcher works, but you also notice small things like idiomatic capitalization (lower_snake_case for functions, UpperCamelCase for types). The original compiler was even written in OCaml. The language borrowed a lot from OCaml and the ML subculture is still really strong on the core development team. That shows through enough to persuade ML-inclined engineers to use it even when they don't need a systems language. I'd say there's a really strong reason the comparison still exists even if they've moved apart over time.

Post reply on HN