Welcome to Snippets of Code, a programming language live journal. The current focus is on the Elixir programming language. Feel free to leave comments or suggestions!
In Elixir, process identifiers (PIDs) are unique data types that function as mailbox addresses. When a process is created using the spawn function, a PID is returned to reference the created process. This allows other processes to send messages and communicate with the new process.
One of the primary benefits of using processes in Elixir is achieving true concurrency. Each process has its own memory space, which enables it to run other processes in the system. Another advantage of using Elixir processes is communicating between processes using message passing. Each process has its mailbox, which can receive messages from other processes.
Let's look at an example to prove the power of Elixir processes. Consider a chat server that allows many users to connect and send messages to each other in real-time. We can create a concurrent system that can handle many connected users using processes.
To create a new process in Elixir, we use the spawn function and pass in the function to be executed by the process as an argument. Using the send function, we can then use the PID of the new process to communicate with it. For example, the following code creates a new process that prints "Hello, world!" to the console:
pid = spawn(fn ->
IO.puts("Hello, world!")
end)
To receive messages in a process, we use the receive block. Here's an example:
pid = spawn(fn ->
receive do
message ->
IO.puts("Received message: #{message}")
end
end)
In this example, we create a new process that waits for a message to be received using the receive block. When a message is received, it prints it to the console.
Processes in Elixir can be linked together so that if one process crashes, it will take down the linked processes with it. We use the Process.link/1 function to link processes. For example, the following code creates a new process that links itself to the primary process and raises an exception to crash itself:
pid = spawn(fn ->
Process.link(self())
raise "Oops!"
end)
In the primary process, we can wait for the crash to happen and print the reason for the crash to the console:
receive do
{'EXIT', _pid, reason} ->
IO.puts("Process crashed: #{reason}")
end
These are just a few examples of how to use processes in Elixir. By leveraging the power of processes, developers can create highly concurrent and fault-tolerant systems that can scale to handle large workloads. Elixir's lightweight processes and message-passing capabilities make it an ideal language for building distributed systems, real-time applications, and other highly concurrent applications.
Weekly Resources
Fetching a Large Amount of Data with Elixir
The Stream module in Elixir provides a way to work with collections lazily and efficiently, processing each record as it arrives, allowing the application to handle extensive data sets more efficiently and scalable way. By wrapping the stream operations in a transaction for data consistency, we can safely execute the stream and prevent data corruption in the event of an error.
ElixirConf 2021 - Sundi Myint - Stunt Doubles | Testing with Mox
The talk presented at ElixirConf 2021 by Sundi Myint focused on testing with Mocks using the Mox library in Elixir. Mock tests are helpful for simulating experiences that you know to be true in the real world but need to be tested in a controlled way consistently. Mox is a library that provides concurrent mocks for Elixir that adhere to set patterns you must follow if you want it to work well for you. Different use cases exist for and against mocks, but they are beneficial when an external call is needed, like an HTTP call to an API. In contrast, if testing something internally, like database calls or querying, it is probably unnecessary to use mocks.