Write a function pmap/2
that applies a given function to each element of a list in parallel.
Example:
pmap(fun (X) -> X*X end, [1,2,3,4])
% [1,4,9,16]
Solution:
pmap(F, L) ->
Ps = [spawn(?MODULE, execute, [F, X, self()]) || X <- L],
[receive
{Pid, X} -> X
end || Pid <- Ps].
execute(F, X, Pid) ->
Pid ! {self(), F(X)}.
Write a function pfilter/2
that filters a list based on a given predicate in parallel.
Example:
pfilter(fun (X) -> X > 2 end, [1,2,3,4])
% [3,4]
Solution:
pfilter(P, L) ->
Ps = [spawn(?MODULE, check, [P, X, self()]) || X <- L],
lists:foldl(fun (Pid, Vo) ->
receive
{Pid, true, X} -> Vo ++ [X];
{Pid, false, _} -> Vo
end
end, [], Ps).
check(P, X, Pid) ->
Pid ! {self(), P(X), X}.
Write a function partition/2
that partitions a list into N chunks.
Example:
partition([1,2,3,4,5,6,7,8,9,10], 3)
% [[1,2,3],[4,5,6],[7,8,9,10]]
Solution:
partition(L, N) ->
M = length(L),
Chunk = M div N,
End = M - Chunk*(N-1),
parthelp(L, N, 1, Chunk, End, []).
parthelp(L, 1, P, _, E, Res) ->
Res ++ [lists:sublist(L, P, E)];
parthelp(L, N, P, C, E, Res) ->
R = lists:sublist(L, P, C),
parthelp(L, N-1, P+C, C, E, Res ++ [R]).
Write a function parfold/3
that folds a list in parallel using a given function.
Example:
parfold(fun (X, Y) -> X + Y end, [1,2,3,4,5,6,7,8,9,10], 3)
% 55
Solution:
%% From previous exercise %%
partition(L, N) ->
M = length(L),
Chunk = M div N,
End = M - Chunk*(N-1),
parthelp(L, N, 1, Chunk, End, []).
parthelp(L, 1, P, _, E, Res) ->
Res ++ [lists:sublist(L, P, E)];
parthelp(L, N, P, C, E, Res) ->
R = lists:sublist(L, P, C),
parthelp(L, N-1, P+C, C, E, Res ++ [R]).
%% % %%
parfold(F, L, N) ->
Ls = partition(L, N),
Ps = [spawn(?MODULE, dofold, [self(), F, X]) || X <- Ls],
[R|Rs] = [receive
{P, V} -> V
end || P <- Ps],
lists:foldl(F, R, Rs).
dofold(Pid, F, [X|Xs]) ->
Pid ! {self(), lists:foldl(F, X, Xs)}.
Write a function master/1
that spawns a list of functions as linked processes and monitors their execution.
Example:
master([fun () -> timer:sleep(1000), io:fwrite("Hello, World!\n") end])
% "Hello, World!\n"
% ok
Solution:
listlink([], Pids) -> Pids;
listlink([F|Fs], Pids) ->
Pid = spawn_link(F),
listlink(Fs, Pids#{Pid => F}).
master(Functions) ->
process_flag(trap_exit, true),
Workers = listlink(Functions, #{}),
master_loop(Workers, length(Functions)).
master_loop(_, 0) ->
ok;
master_loop(Workers, Count) ->
receive
{'EXIT', _, normal} ->
master_loop(Workers, Count-1);
{'EXIT', Pid, _} ->
#{Pid := Fun} = Workers,
Child = spawn_link(Fun),
master_loop(Workers#{Child => Fun}, Count)
end.