Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to save state in an Erlang process?

Tags:

erlang

I am learning Erlang and trying to figure out how I can, and should, save state inside a process.

For example, I am trying to write a program that given a list of numbers in a file, tells me whether a number appears in that file. My approach is to uses two processes

  • cache which reads the content of the file into a set, then waits for numbers to check, and then replies whether they appear in the set.

    is_member_loop(Data_file) ->
        Numbers = read_numbers(Data_file),
        receive
            {From, Number} ->
                From ! {self(), lists:member(Number, Numbers)},
                is_member_loop(Data_file)
        end.
    
  • client which sends numbers to cache and waits for the true or false response.

    check_number(Number) ->
        NumbersPid ! {self(), Number},
        receive
            {NumbersPid, Is_member} ->
                Is_member
        end.
    

This approach is obviously naive since the file is read for every request. However, I am quite new at Erlang and it is unclear to me what would be the preferred way of keeping state between different requests.

Should I be using the process dictionary? Is there a different mechanism I am not aware of for that sort of process state?

Update

The most obvious solution, as suggested by user601836, is to pass the set of numbers as a param to is_member_loop instead of the filename. It seems to be a common idiom in Erlang and there is a good example in the fantastic online book Learn you some Erlang.

I think, however, that the question still holds for more complex state that I'd want to preserve in my process.

like image 397
Rodrigue Avatar asked May 17 '12 10:05

Rodrigue


People also ask

What is a PID in Erlang?

Each process in erlang has a process identifier ( Pid ) in this format <x.x.x> , x being a natural number. Below is an example of a Pid <0.1252.0> Pid can be used to send messages to the process using 'bang' ( ! ), also Pid can be bounded to a variable, both are shown below. MyProcessId = self().

What is an Erlang process?

Erlang processes are lightweight, operate in (memory) isolation from other processes, and are scheduled by Erlang's Virtual Machine (VM). The creation time of process is very low, the memory footprint of a just spawned process is very small, and a single Erlang VM can have millions of processes running.

How do I terminate a process in Erlang?

A process can terminate itself by calling one of the BIFs exit(Reason), erlang:error(Reason), erlang:error(Reason, Args), erlang:fault(Reason) or erlang:fault(Reason, Args). The process then terminates with reason Reason for exit/1 or {Reason,Stack} for the others.


1 Answers

Simple solution, you can pass to your function is_member_loop(Data_file) the list of numbers rather then the file name.

The best solution when you deal with a state consists in using a gen_server. To learn more you should take a look at records and gen_server behaviour (this may also be useful).

In practice:

1) start with a module (yourmodule.erl) based on gen_server behaviour 2) read your file in the init function of the gen_server and pass it as state field:

init([]) ->
    Numbers = read_numbers(Data_file),
{ok, #state{numbers=Numbers}}.

3) write a function which will be used to trigger a call to the gen_server

check_number(Number) ->
    gen_server:call(?MODULE, {check_number, Number}).

4) write the code in order to handle messages triggered from your function

handle_call({check_number, Number}, _From, #state{numbers=Numbers} = State) ->
    Reply = lists:member(Number, Numbers)},
{reply, Reply, State};

handle_call(_Request, _From, State) ->
    Reply = ok,
{reply, Reply, State}.

5) export from yourmodule.erl function check_number

-export([check_number/1]).

Two things to be explained about point 4:

a) we extract values inside the record State using pattern matching

b) As you may see I left the generic handle call, otherwise your gen_server will fail due to wrong pattern matching whenever a message different from {check_number, Number} is received

Note: if you are new to erlang, don't use process dictionary

like image 159
user601836 Avatar answered Nov 09 '22 02:11

user601836