[erlang-questions] performance on multicore computer

Jesper Louis Andersen jesper.louis.andersen@REDACTED
Sat Oct 23 02:40:21 CEST 2010


On Sat, Oct 23, 2010 at 1:07 AM, Jiansen He <jiansenhe@REDACTED> wrote:

This part:

> %% -- generate all sequences of length exactly n starting at index i or
> later
> %% gen_ :: Int -> Int -> [String] -> AssocList [String] Int
> gen_ (_, _, [], From) -> From ! {seq, []};
> gen_ (I, N, [H | T], From) ->
>  if
>     N > length([H | T]) -> From ! {seq, []};
>     true ->
>        gen_(I+1, N, T, self()),
>        receive
>          {seq, Seq} ->
>            From ! {seq, insert({takeN(N, [H | T]), I}, Seq)};
>          Msg ->
>            io:format("unrecognized message in gen_/4: ~n")
>        end
>  end.

Seem a bit odd to me. If I read it right, you are essentially running
a recursive loop by messaging yourself the result of the recursive
calls. In other words I think you can rewrite this into a normal
recursive loop. This will definitely be faster as the receives simply
serialize into a long chain, the mailbox only containing a single
message all the time.

> %% -- generate all sequences of length at most n
> %% gen :: Int -> [String] -> AssocList [String] Int
> gen(0, _, From) ->
>     From ! {seq, []};
> gen(N, L, From) ->
>     spawn(concordance_1_1, gen_, [0, N, L, self()]),
>     spawn(concordance_1_1, gen, [(N-1), L, self()]),
>     gen_loop(2, [], From).
>
> gen_loop(0, Seq, From) ->
>     From ! {seq, Seq};
> gen_loop(N, Seq, From) ->
>     receive
>       {seq, Seq_} ->
>         gen_loop(N-1, merge(Seq, Seq_), From);
>       Msg ->
>            io:format("f unrecognized message in gen_loop/3: ")
>     end.

These seem ok from a quick glance. And they seem to be in accordance
with the Haskell code below.

> In Haskell, I could simply write code like this:
>
> -- generate all sequences of length at most n
> gen :: Int -> [String] -> AssocList [String] Int
> gen 0 _ = []
> --gen n l = merge sqs_len_n sqs_up_to_n1
> gen n l = sqs_len_n `par` sqs_up_to_n1 `pseq` (merge sqs_len_n sqs_up_to_n1)
>             where sqs_up_to_n1 = (gen (n-1) l)
>                        sqs_len_n = (gen' 0 n l)

The `par` combinator is perhaps mostly akin to the rpc:parallel_eval/1
call in the Erlang/OTP stdlib by the way. Note however that
parallel_eval can span multiple machines (nodes in Erlang-terminology)
in a distributed fashion, which `par` cannot. Also, by using parallel
eval, you could eliminate the gen_loop from your code and fold the
merge into gen like in the Haskell version.



-- 
J.


More information about the erlang-questions mailing list