Closing Channels in Erlang
In this example, we’ll use a jobs
process to communicate work to be done from the main process to a worker process. When we have no more jobs for the worker, we’ll send a special message to indicate completion.
-module(closing_channels).
-export([main/0]).
main() ->
Jobs = spawn(fun() -> jobs_process([]) end),
Done = spawn(fun() -> done_process() end),
% This is the worker process. It repeatedly receives
% messages from Jobs. When it receives the 'close' atom,
% it knows that all jobs have been processed.
Worker = spawn(fun() -> worker_process(Jobs, Done) end),
% This sends 3 jobs to the worker via the Jobs process
[Jobs ! {job, J} || J <- lists:seq(1, 3)],
io:format("sent all jobs~n"),
Jobs ! close,
% We await the worker using a synchronization approach
receive
done -> ok
end,
% Checking if the Jobs process is still alive
case is_process_alive(Jobs) of
true -> io:format("Jobs process is still alive~n");
false -> io:format("Jobs process has terminated~n")
end.
jobs_process(Queue) ->
receive
{job, J} ->
jobs_process([J | Queue]);
{get_job, Pid} when Queue /= [] ->
[Job | Rest] = lists:reverse(Queue),
Pid ! {job, Job},
jobs_process(Rest);
{get_job, Pid} when Queue == [] ->
Pid ! no_more_jobs,
jobs_process([]);
close when Queue == [] ->
exit(normal);
close ->
jobs_process(Queue)
end.
worker_process(Jobs, Done) ->
Jobs ! {get_job, self()},
receive
{job, J} ->
io:format("received job ~p~n", [J]),
worker_process(Jobs, Done);
no_more_jobs ->
io:format("received all jobs~n"),
Done ! done
end.
done_process() ->
receive
done -> ok
end.
To run the program, save it as closing_channels.erl
and use the Erlang shell:
$ erl
1> c(closing_channels).
{ok,closing_channels}
2> closing_channels:main().
sent job 1
received job 1
sent job 2
received job 2
sent job 3
received job 3
sent all jobs
received all jobs
Jobs process has terminated
ok
In this Erlang version, we use processes and message passing to mimic the behavior of channels in Go. The jobs_process
acts as a queue for jobs, the worker_process
receives and processes jobs, and the done_process
is used for synchronization.
The concept of closing a channel is simulated by sending a close
message to the jobs_process
. When the jobs_process
receives this message and its queue is empty, it terminates.
The worker process keeps requesting jobs until it receives a no_more_jobs
message, at which point it signals completion to the done_process
.
Finally, we check if the Jobs
process is still alive, which is analogous to checking if a channel is closed in Go.
This example demonstrates how Erlang’s processes and message passing can be used to implement patterns similar to Go’s goroutines and channels.