Every Erlang Applications consist of many processes. What makes Erlang a good choice for concurrent applications are :
- Immutable data
- No Shared memory
- Lightweight Processes
Erlang is designed for massive concurrency. A process in Erlang is lightweight and have a very small memory footprint we can create hundreds of them without causing any scheduling overhead. We can easily create or terminate a process.
Erlang processes communicate with each other by passing messages. Its more like two people talking with each other. Each process have a message queue which will hold the messages sent to the process until its processed.
Processes in an Erlang application are scheduled for execution by a Scheduler. SMP support was added to Erlang in OTP R11B .
On a multi-core machine the VM starts one Scheduler thread per CPU Core by default. That is on a machine with 2 Cores there will be 2 Schedulers running.
When you start the Erlang emulator using
erl command you can see these details [smp:4:4] :
Erlang/OTP 21 [erts-10.0.5] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1]
You can tune this using emulator flags. Use the flag +S Schedulers:Schedulersonline Max value for this is 1024
➜ ~ erl +S 2:2 Erlang/OTP 21 [erts-10.0.5] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:1]
Each scheduler will have its own run queue. Which consist of processes that are ready for execution. The runtime also have a process migration logic, which ensure processes are fairly distributed among the Cores/Schedulers. Also the runtime will pause the scheduler thread under light load and this help in saving power and the core can be put in power saving mode.
Each process is assigned a weight called (Reduction) which is based on the statements and function calls in the program. Each process is allowed to execute for the reduction count it have and then its preempted for next process in queue. This ensure no process can block the whole application.
Details of how much reduction each statement or function carry is purposefully not document to prevent premature optimizations and might change from one release or hardware architecture to other.
Erlang processes does not share memory. Each one have a separate :
- Message Box
The stack and heap are allocated on same memory block and they grow towards each other. Once they meet a Garbage collection is triggered. This is not a stop-the-world collection. Only the particular process's memory is collected. Others continue with normal operations.
Another advantage of not sharing memory is when a process crash the memory can be safely recollected, avoiding any leaks. This is not trivial in case of languages which use shared memory for eg: with Threads for concurrency.