Hacker News new | ask | show | jobs
by cvik 3781 days ago
To my knowledge, Erlang uses a cooperative scheduler. The process itself counts downs its reductions and yields when it is time. The programmer can call erlang:yield() to do this before time if he wants. Calling something like receive will also yield. I guess it comes down to definitions, but since Erlang is said to have only soft real-time (as opposed to hard real-time) properties, this makes more sense. The schedulers doesn't give any guarantees as to when a process gets to run and the scheduler never really preempts a process. Again, to my knowledge.

Great article though!

2 comments

That's a good pint! I also can say that it is a matter of perspective. From an Erlang developer point of view, the processes are executing in a preemptive manner without telling them when to yield. The important factor is the reduction limit of the actors as well as being reentrant. It guarantees that each actor will sure yield even if it is still running and have something to do, and will be selected whenever scheduler select them again for execution.
I was also confused by this phrasing. The only thing I could think of was that from the programmer's perspective, it's not cooperative (you don't have to call yield), but that's also true of threads.

I see people down thread repeating this claim. Can anyone explain how the scheduler is preemptive?

You are absolutely correct, the schedulers never preempt a process in the classical sense, but from an Erlang code perspective, the system behaves as if it would be preemptive. The schedulers are actually running a byte code interpreter and the interpreter will switch processes once a certain number of reductions is reached (or the code yields). This breaks down when running native code in the form of NIFs - it is entirely possible to block a scheduler indefinitely while running native code.
I like to think of it as preemptive because (putting NIFs aside) it's not possible for a single process to completely block the entire scheduler, even if it ends up in an infinite CPU bound loop.

So in other words, a task (i.e. process) doesn't have to cooperate with others. It can do whatever it wants, be it I/O or CPU bound, and doesn't have to yield explicitly. Due to aggressive "preemption" it won't block other pending tasks significantly.

In contrast, if this is not guaranteed (which is not in most other Erlang "alternatives" I've looked at), then a task might accidentally paralyse large portion of the system.