一个二郎演员小演示
Posted
技术标签:
【中文标题】一个二郎演员小演示【英文标题】:a erlang actor little demo 【发布时间】:2020-04-11 09:59:51 【问题描述】:我是Erlang的菜鸟,写蜘蛛的代码很累:
-module(http).
-compile([export_all]).
init() ->
ssl:start(),
inets:start(),
register(m, spawn(fun() -> loop() end)),
register(fetch, spawn(fun() -> x() end)),
ok.
start() ->
L1 = [114689,114688,114691,114690], % detail page 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://example.com", % url demo
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.
现在,当我执行代码时,进程将立即终止,记录:
我有两个问题:
-
我该如何解决这个问题?
如果我在
L1
有几万个id,怎么解决?产生几十个演员?如果是,你如何决定哪个演员receive
哪个id?
【问题讨论】:
【参考方案1】:1) 而不是在loop()
周围包装匿名函数:
register(m, spawn(fun() -> loop() end)),
您可以拨打spawn/3:
register(m, spawn(?MODULE, loop, []) ),
这里也一样:
register(fetch, spawn(fun() -> x() end)),
不。在 escript 中调用 spawn/3 不起作用 - 除非您使用以下命令预编译脚本:
escript -c myscript.erl
2) escript 创建一个执行您定义的main/1
函数的进程。您的 main/1
函数如下所示:
main(_) ->
init(),
start().
init()
函数不会循环,因此它会在它调用的所有函数返回后结束,即ssl:start()
、inets:start()
、register()
。你的start()
函数也不会循环,所以在start()
返回之后,main()
返回并且因为执行main()
函数的进程没有什么可做的,所以它结束了。
3)
我如何解决这个问题?
Http post 请求在计算机处理速度方面是永恒的,并且涉及等待,因此您可以通过同时执行多个 post 请求而不是顺序执行它们来加速您的代码。在 erlang 中,您同时执行事物的方式是产生额外的进程。在您的情况下,这意味着为每个发布请求生成一个新进程。
您的主进程可以是一个无限循环,位于接收等待消息中,如下所示:
main(_) ->
init(),
loop().
init()
看起来像这样:
init() ->
ssl:start(),
inets:start(),
register(loop, self()),
ok.
然后您可以创建一个类似start()
的用户界面函数来生成发布请求:
start() ->
L1 = [114689,114688,114691,114690], % detail page id
lists:foreach(fun(Gid) ->
io:format("~p ~n", [Gid]),
spawn(?MODULE, http_post, [Gid])
end, L1).
---回复评论---
这是一个例子:
%First line cannot have erlang code.
main(_) ->
init(),
start().
init() ->
ssl:start(),
inets:start().
start() ->
L1 = [1, 2, 3, 4],
Self = self(),
Pids = lists:map(fun(Gid) ->
Pid = spawn(fun() -> http_post(Gid, Self) end),
io:format("Spawned process with Gid=~w, Pid=~w~n", [Gid, Pid]),
Pid
end, L1),
io:format("Pids = ~w~n", [Pids]),
lists:foreach(
fun(Pid) ->
receive
no_res, Gid, Pid ->
io:format("no response! (Gid=~w, Pid=~w)~n", [Gid, Pid]);
have_res, Gid, Pid, Reply ->
io:format("got response: ~p~n(Gid=~w, Pid=~w)~n~n",
[Reply, Gid, Pid]);
Pid, Gid, Error ->
io:format("Error:~n(Gid=~w, Pid=~w)~n~p~n", [Gid, Pid, Error])
end
end, Pids).
http_post(Gid, Pid) ->
URL = "http://localhost:8000/cgi-bin/read_json.py", % url demo
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]),
Reply = no_res, Gid, self() ,
Pid ! Reply;
true ->
io:format("N: ~p ~n", [Gid]),
Reply = have_res, Gid, self(), ResBody ,
Pid ! Reply
end;
error, _Reason=Error ->
Pid ! Gid, self(), Error;
Other ->
Pid ! Gid, self(), Other
end.
如果我在 L1 有数万个 id,如何解决?
同样的方法。十万个进程在erlang中不算很多。
【讨论】:
是的,您的解决方案没问题。但是我必须打开两个erlang shell。如果我只想使用 escript 执行代码来获得像 Python 或 javascript 这样的脚本语言的结果?如果 escript 不能,其他 Erlang 程序如何在主要进展中获得演员结果。 @riskers,请参阅我添加到答案底部的完整示例。 好吧,我以前在 Golang 中也做过同样的事情:创建 500 个通道来处理十万个 http 请求。现在我在 Erlang 中生成了 500 个 Actor,如何在确定性 Actor 中分发十万个 http 请求。 @riskers,我认为您不需要在 erlang 中为 http 请求创建线程池,但是 erlang 中的线程池的编程方式与任何其他语言中的线程池类似——逻辑是一样的。 erlang 工作进程将在接收中等待描述需要完成的工作的消息,例如一个 url,当没有更多工作要做时,您向工作进程发送done
消息,这会导致接收停止循环,并且工作人员死亡。
....或者,您可以使用第三方库,如poolboy、poolboy以上是关于一个二郎演员小演示的主要内容,如果未能解决你的问题,请参考以下文章