Next lesson playing in 5 seconds

Cancel
  • Overview
  • Transcript

3.1 Processes

Hi, and welcome back to get started with Elixir. In this lesson I'm going to teach you about processes, our first concurrency pattern. [INAUDIBLE] BEAM VM has the concept of processes that get run separately from the main code. To execute code in a separate BEAM process, you will have to spawn a new one from the Elixir code. This happens with the spawn function. It's important to know that processes don't share memory. This also means that everything the process needs will be copied to an isolated memory space for the process. Unlike real operating system processes, it's actually very cheap to spawn new processes in Elixir. So developers do it a lot. When you spawn a new process, you will receive a PID, or Process Identifier, as a return value. A PID is also a core data type. Processes can receive messages so you can interact with them from the outside. You can send a message with a send function. It takes a PID and a value. It can be any Elixir data type. To handle such messages, every process in the BEAM dm has a mailbox. You have to manage processing messages from the mailbox in your code. And this can be done with the receive function. Like with a cont statement, receive allows for pattern matching, but if you don't hand the case, the message will stay in the mail box and might crash your process. Speaking of crashing, let's talk about process death. If your process raises an error and exits, the process that spawned it might not be notified. This loose coupling can't be good, since it will only bring down the process that produced an error. And not take down the rest of your application. But it also is bad because no one notices it. A process can die if someone kills it with process, exit also. If you use spawn_link instead of spawn, the processes will be linked together and the faith is shared. If the spawn process dies, the current process will as well. To avoid this happening, you can trap the exit and to a spawn process dying. This works by handling messages on the mailbox. We also have the spawn_monitor, which will watch processes and get notified about status updates. For instance, a process going down. Let's look at an example, I'm going to do the calculation of Fibonacci numbers from a list that contains the iteration limit for each number. For this, we need a function called fitlist that takes list as an argument. In the function, we are going to pipe the list to enum.map, which calls another function. Spawn calculation with the item as the first parameter, and the current process bit obtained by calling self as the second. The spawn calculation function will initiate a calculation of Fibonacci numbers. Here, I'm calling spawn_link, and pass anonymous function that will send a message to the parent containing its pit and the result of the call to fit, which we'll implement in a minute. As spawn_link returns the pit of the spawned process, we now have a list of those. We can call enum map again and this time pause, collect result one. This function has a receive block. That matches the pit with the past pit, and returns the result. This way, all the results are in the correct order. Now all that's missing is the Fibonacci function itself. I'm going to use a version that looks a bit more complicated than you might be used to. First I'm defining the public fib function that takes an argument and then this will then be passed to another fib function that takes three parameters. The first one is the current Fibonacci value, the second one is the next Fibonacci value. And the third one is the remaining number of calculations. Then I'm going to define the case where N has reached zero. Along the interest in the value A, which will be returned. Finally, we're going to do the recursive part, recall fib again was the first parameter sd, the second is a + b and the last one was n- 1. It look so complicated because we take advantage of tail call optimization. TCO leads to lower memory use when you have deep precaution. By only keeping one function called in memory and this is only rocking if function is calling itself, that's the last action. So far so good, let's try it out. In iex, I'm going to call Fibonacci fib_list and pass a range from 1 to 20. It returns to complete Fibonacci sequence between those borders. To recap, you can spawn new processes with spawn. You can send messages to processes with send and handle them with receive. To share the fate of two processes, use spawn_link. To monitor a process, use spawn_monitor. In the next lesson, we are going to talk about the open telecom platform, short OTP, and one of it's most important components, the GenServer. See you there.

Back to the top