Erlang 新手 - 并发和消息传递
Erlang newbie - concurrency and message passing
我对编程和全新的 erlang 还是个新手(2 周的新手!)。我稍微编辑了一下,至少它会编译并且 运行。但我仍然无法弄清楚将结果发送到 "joiner process" 以加入所有单独结果的概念。
它确实拆分并发送 "chunks" 接收到的数据块来计算块数。只是不知道如何让所有这些过程加入他们各自的结果。我有点理解下面的概念,但不知道它是如何实现的。我已经尝试了很多天和几个小时来达到这一点,但是如果没有错误或未绑定变量等,我无法让它做任何事情。
-module (ccharcount1d).
-compile(export_all).
load(F)->
{ok, Bin} = file:read_file(F),
List=binary_to_list(Bin),
Ls=string:to_lower(List),
Length=round(length(List)/20),
Collect_Results = spawn(ccharcount1d, collect_results, []),
Sl=split(Ls,Length),
io:fwrite("Loaded, Split, and sent to multiple processes~n").
%%splits txt file into "chunks" and sends those "chunks" to be processed
split([],_)->[];
split(List,Length)->
S1=string:substr(List,1,Length),
case length(List) > Length of
true->S2=string:substr(List,Length+1,length(List)),
Process_Split = spawn(ccharcount1d,receive_splits,[]),
Process_Split ! {self(), S1};
false->S2=[],
Process_Split = spawn(ccharcount1d,receive_splits,[]),
Process_Split ! {self(), S1}
end,
[S1]++split(S2,Length).
%%recieves the split "chunks" and counts the results
receive_splits()->
receive
{From, S1} ->
Result=go(S1)
%Collect_Results ! Result
end.
collect_results()->
receive
{Process_Split, Result} ->
Result=join([],Result)
end.
join([],[])->[];
join([],R)->R;
join([H1 |T1],[H2|T2])->
{C,N}=H1,
{C1,N1}=H2,
[{C1,N+N1}]++join(T1,T2).
count(Ch, [],N)->N;
count(Ch, [H|T],N) ->
case Ch==H of
true-> count(Ch,T,N+1);
false -> count(Ch,T,N)
end.
go(L)->
Alph=[$a,$b,$c,$d,$e,$f,$g,$h,$i,$j,$k,$l,$m,$n,$o,$p,$q,$r,$s,$t,$u,$v,$w,$x,$y,$z],
rgo(Alph,L,[]).
rgo([H|T],L,Result)->
N=count(H,L,0),
Result2=Result++[{[H],N}],
rgo(T,L,Result2);
rgo([],L,Result)-> Result.
您需要同步go函数的输出。
不要在 go 中生成函数,因为我看到所有结果都将进入不同的过程(receive_results)。
最好的解决方案是只在加载函数中产生一个用于连接结果的进程(此过程将 self() 作为输入,以便它可以将最终结果发送回加载函数)。然后传递该连接进程引用(J_PID) 发送回结果以加入的所有工作进程 process.Join 进程是一种循环 receive_results.Loop 当所有块都是 processed.Add 终止加入的子句时终止 process.While终止,加入过程会将结果发送回加载函数。
Sudo 代码:
J_PID = spawn join(self())
溢出(J_PID,....)
wait_for_result(接收结果 -> R)
again, i'm new. I'm understanding the concept. I'm not understanding
the syntax. the how to "pass a Pid to a worker process"
start() ->
Work = ...,
JoinPid = spawn(fun() -> join_func([]) end),
WorkerPid = spawn(fun() -> worker_func(JoinPid, Work) end), %Pass JoinPid to worker process.
...
join_func(Acc) ->
receive
Result ->
join_func([Result|Acc]); %Recursive function call--the life blood of all functional languages.
...
end
worker_func(JoinPid, Work) ->
Result = ... Work ...,
JoinPid ! Result. %Worker process uses JoinPid to send back the results.
另外,看看这个:
8> [$a, $b, $c].
"abc"
9> "abc".
"abc"
输出显示 [$a, $b, $c]
等同于 "abc"
。这意味着你可以这样写:
[$a,$b,$c,$d,$e,$f,$g,$h,$i,$j,$k,$l,$m,$n,$o,$p,$q,$r,$s,$t,$u,$v,$w,$x,$y,$z]
像这样更简洁:
"abcdefghijklmnopqrstuvwxyz"
更甚者,像这样:
11> lists:seq(97, 122).
"abcdefghijklmnopqrstuvwxyz"
我对编程和全新的 erlang 还是个新手(2 周的新手!)。我稍微编辑了一下,至少它会编译并且 运行。但我仍然无法弄清楚将结果发送到 "joiner process" 以加入所有单独结果的概念。
它确实拆分并发送 "chunks" 接收到的数据块来计算块数。只是不知道如何让所有这些过程加入他们各自的结果。我有点理解下面的概念,但不知道它是如何实现的。我已经尝试了很多天和几个小时来达到这一点,但是如果没有错误或未绑定变量等,我无法让它做任何事情。
-module (ccharcount1d).
-compile(export_all).
load(F)->
{ok, Bin} = file:read_file(F),
List=binary_to_list(Bin),
Ls=string:to_lower(List),
Length=round(length(List)/20),
Collect_Results = spawn(ccharcount1d, collect_results, []),
Sl=split(Ls,Length),
io:fwrite("Loaded, Split, and sent to multiple processes~n").
%%splits txt file into "chunks" and sends those "chunks" to be processed
split([],_)->[];
split(List,Length)->
S1=string:substr(List,1,Length),
case length(List) > Length of
true->S2=string:substr(List,Length+1,length(List)),
Process_Split = spawn(ccharcount1d,receive_splits,[]),
Process_Split ! {self(), S1};
false->S2=[],
Process_Split = spawn(ccharcount1d,receive_splits,[]),
Process_Split ! {self(), S1}
end,
[S1]++split(S2,Length).
%%recieves the split "chunks" and counts the results
receive_splits()->
receive
{From, S1} ->
Result=go(S1)
%Collect_Results ! Result
end.
collect_results()->
receive
{Process_Split, Result} ->
Result=join([],Result)
end.
join([],[])->[];
join([],R)->R;
join([H1 |T1],[H2|T2])->
{C,N}=H1,
{C1,N1}=H2,
[{C1,N+N1}]++join(T1,T2).
count(Ch, [],N)->N;
count(Ch, [H|T],N) ->
case Ch==H of
true-> count(Ch,T,N+1);
false -> count(Ch,T,N)
end.
go(L)->
Alph=[$a,$b,$c,$d,$e,$f,$g,$h,$i,$j,$k,$l,$m,$n,$o,$p,$q,$r,$s,$t,$u,$v,$w,$x,$y,$z],
rgo(Alph,L,[]).
rgo([H|T],L,Result)->
N=count(H,L,0),
Result2=Result++[{[H],N}],
rgo(T,L,Result2);
rgo([],L,Result)-> Result.
您需要同步go函数的输出。 不要在 go 中生成函数,因为我看到所有结果都将进入不同的过程(receive_results)。
最好的解决方案是只在加载函数中产生一个用于连接结果的进程(此过程将 self() 作为输入,以便它可以将最终结果发送回加载函数)。然后传递该连接进程引用(J_PID) 发送回结果以加入的所有工作进程 process.Join 进程是一种循环 receive_results.Loop 当所有块都是 processed.Add 终止加入的子句时终止 process.While终止,加入过程会将结果发送回加载函数。
Sudo 代码:
J_PID = spawn join(self())
溢出(J_PID,....)
wait_for_result(接收结果 -> R)
again, i'm new. I'm understanding the concept. I'm not understanding the syntax. the how to "pass a Pid to a worker process"
start() ->
Work = ...,
JoinPid = spawn(fun() -> join_func([]) end),
WorkerPid = spawn(fun() -> worker_func(JoinPid, Work) end), %Pass JoinPid to worker process.
...
join_func(Acc) ->
receive
Result ->
join_func([Result|Acc]); %Recursive function call--the life blood of all functional languages.
...
end
worker_func(JoinPid, Work) ->
Result = ... Work ...,
JoinPid ! Result. %Worker process uses JoinPid to send back the results.
另外,看看这个:
8> [$a, $b, $c].
"abc"
9> "abc".
"abc"
输出显示 [$a, $b, $c]
等同于 "abc"
。这意味着你可以这样写:
[$a,$b,$c,$d,$e,$f,$g,$h,$i,$j,$k,$l,$m,$n,$o,$p,$q,$r,$s,$t,$u,$v,$w,$x,$y,$z]
像这样更简洁:
"abcdefghijklmnopqrstuvwxyz"
更甚者,像这样:
11> lists:seq(97, 122).
"abcdefghijklmnopqrstuvwxyz"