httpc + многие запросы в spawn не работали
Я пытался использовать httpc-модуль Эрланга для высоких одновременных запросов
Мой код для многих запросов в spawn не работал:
-module(t).
-compile(export_all).
start() ->
ssl:start(),
inets:start( httpc, [{profile, default}] ),
httpc:set_options([{max_sessions, 200}, {pipeline_timeout, 20000}], default),
{ok, Device} = file:open("c:\urls.txt", read),
read_each_line(Device).
read_each_line(Device) ->
case io:get_line(Device, "") of
eof -> file:close(Device);
Line -> go( string:substr(Line, 1,length(Line)-1)),
read_each_line(Device)
end.
go(Url)->
spawn(t,geturl, [Url] ).
geturl(Url)->
UrlHTTP=lists:concat(["http://www.", Url]),
io:format(UrlHTTP),io:format("~n"),
{ok, RequestId}=httpc:request(get,{UrlHTTP,[{"User-Agent", "Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.8.131 Version/11.10"}]}, [],[{sync, false}]),
receive
{http, {RequestId, {_HttpOk, _ResponseHeaders, Body}}} -> io:format("ok"),ok
end.
httpc: запрос не получен в теле HTML - если я могу использовать спавн в
go(Url)->
spawn(t,geturl, [Url] ).
http://erlang.org/doc/man/httpc.html
Заметка
Если возможно, клиент будет поддерживать свои соединения и использовать постоянные соединения с конвейером или без него, в зависимости от конфигурации и текущих обстоятельств. Спецификация HTTP/1.1 не предоставляет руководящих указаний относительно того, сколько запросов было бы идеально для отправки по постоянному соединению, это очень сильно зависит от приложения. Обратите внимание, что очень длинная очередь запросов может вызвать задержку, воспринимаемую пользователем, так как более ранние запросы могут занять много времени. Спецификация HTTP/1.1 предлагает ограничение в 2 постоянных соединения на сервер, которое является значением по умолчанию для параметра max_sessions
urls.txt содержит разные URL - например,
google.com
amazon.com
alibaba.com
...
В чем дело?
1 ответ
Для меня это работает, если я запускаю инет без аргументов inets:start()
по умолчанию для запуска службы httpc. Я не играл весь код, так как у меня нет примера urls.txt, но в оболочке я получаю ответ на запрос http.
Когда я пытаюсь запустить inets, используя inets:start( httpc, [{profile, default}] )
Я получаю возвращаемое значение: {error,inets_not_started}
,
Вы должны проверить возвращаемое значение запуска приложения, чтобы отследить потенциальные проблемы:
...
ok = ssl:start(),
ok = inets:etart(),
...
или, если приложение уже может быть запущено, используйте такую функцию:
...
ok = ensure_start(ssl),
ok = ensure_start(inets),
...
ensure_start(M) ->
case M:start() of
ok -> ok;
{error,{already_started,M}} -> ok;
Other -> Other
end.
[править 2 - небольшое улучшение кода]
Я тестировал этот код, и он работает на моем ПК. Обратите внимание, что вы используете '\' в строке для доступа к файлу, это escape-последовательность, которая приводит к сбою строки.
-module(t).
-compile(export_all).
start() -> start(2000).
% To is a parameter which is passed to getUrl to change the timeout value
% you can play with it to see the request queue effect, and the very variable time of
% sites response. default value is 2 seconds
start(To) ->
ok = ensure_start(ssl),
ok = ensure_start(inets),
ok = httpc:set_options([{max_sessions, 200}, {pipeline_timeout, 20000}], default),
{ok, Device} = file:open("D:/urls.txt", read),
read_each_line(Device,To).
read_each_line(Device,To) ->
case io:get_line(Device, "") of
eof -> file:close(Device);
Line -> go( string:substr(Line, 1,length(Line)-1),To),
read_each_line(Device,To)
end.
go(Url,To)->
spawn(t,geturl, [Url,To] ).
geturl(Url,To)->
UrlHTTP=lists:concat(["http://www.", Url]),
io:format(UrlHTTP), io:format("~n"),
{ok, RequestId}=httpc:request(get,{UrlHTTP,[{"User-Agent", "Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.8.131 Version/11.10"}]}, [],[{sync, false}]),
M = receive
{http, {RequestId, {_HttpOk, _ResponseHeaders, _Body}}} -> ok
after To ->
not_ok
end,
io:format("httprequest to ~p: ~p~n",[UrlHTTP,M]).
ensure_start(M) ->
case M:start() of
ok -> ok;
{error,{already_started,M}} -> ok;
Other -> Other
end.
и в консоли:
1> t:start().
http://www.povray.org
http://www.google.com
http://www.yahoo.com
ok
httprequest to "http://www.google.com": ok
httprequest to "http://www.povray.org": ok
httprequest to "http://www.yahoo.com": ok
2> t:start().
http://www.povray.org
http://www.google.com
http://www.yahoo.com
ok
httprequest to "http://www.google.com": ok
httprequest to "http://www.povray.org": ok
httprequest to "http://www.yahoo.com": ok
3>
Обратите внимание, что благодаря sure_start вы можете запустить приложение дважды.
Я также проверил с плохим URL, и это обнаружено.
Мой тест включает только 3 URL, я думаю, что если их будет много, время для получения ответа увеличится, потому что цикл к процессам порождения выполняется быстрее, чем сам запрос. Таким образом, вы должны ожидать в какой-то момент проблемы с тайм-аутом. Также может быть некоторое ограничение в http-клиенте, я не проверял документ по этому конкретному вопросу.