Erlang 初学者对 Actor 的困惑(有例子)

初学 Erlang,对 actor 模型刚刚了解,写了一段代码,做爬虫使用:

-module(http).
-compile([export_all]).

init() ->
  ssl:start(),
  inets:start(),
  register(m, spawn(fun() -> loop() end)),
  % loop(),
  register(fetch, spawn(fun() -> x() end)),
  ok.

start() ->
  L1 = [114689,114688,114691,114690,114695,114694,114697,114699,114698,114701,114700,114702,114705,114707,114706,110127,110128,110131,110132,110135,110136,110138,110143,110145,110144,110146,110149,110151,110150,110154,110157,110156,110159,110158,110161,110163], % 以这些详情页 id 做例子

  lists:map(fun(Gid) ->
    io:format("~p ~n", [Gid]),
    fetch ! {go, Gid}
  end, L1),

  m ! done,

  done.

main(_) ->
  init(),
  start().

loop() ->
  io:fwrite("this is in loop!!"),
  receive
    {no_res, Gid} ->
      io:format("~p no res ! ~n", [Gid]),
      loop();
    {have_res, Gid} ->
      io:format("~p have res ! ~n", [Gid]),
      loop();
    done ->
      io:format("wowowow", [])
  end.

x() ->
  receive
    {go, Gid} ->
      http_post(Gid);
    _ ->
      ready
  end.

http_post(Gid) ->
  URL = "https://xxx.com", % 以这个 url 为例子
  Type = "application/json",
  ReqArr = ["[{\"id\": \"", integer_to_list(Gid), "\"}]"],
  ReqBody = string:join(ReqArr, ""),

  case httpc:request(post, {URL, [], Type, ReqBody}, [], []) of
    {ok, {_, _, ResBody}} ->
      if
        length(ResBody) =:= 0 ->
          io:format("Y: ~p ~n", [Gid]);
          m ! {no_res, Gid};
        true ->
          io:format("N: ~p ~n", [Gid])
          m ! {have_res, Gid}
      end;
    {error, Reason} ->
      io:format("error cause ~p~n", [Reason]);
    _ ->
      io:format("error cause ~n", [])
  end.

现在的问题是,我执行以后立刻就执行到 start()done 了,主进程立马结束,有没有什么办法让主进程等待这些请求完成再结束呢?

还有,我这样写总感觉不对,有没有什么办法改进呢?

请指教。

阅读 371
评论
    1 个回答
    • 90

    就本例而言:

    start() ->
      L1 = [114689,1146881,110158,110161,110163],
    
      lists:map(fun(Gid) ->
        io:format("~p ~n", [Gid]),
        fetch ! {self(),go, Gid} %% 这里发的时候带上自己的pid,worker的工作完成后通知主进程
      end, L1),
      m ! done,
      wait(length(L1)), %% 等待任务完成
      done.
      
    wait(0)->ok;
    wait(N)->
        receive
            _->
                wait(N-1)
        end.

    改进的写法:
    看看gen_server的用法。

      撰写回答

      登录后参与交流、获取后续更新提醒