Upload
ilya-averyanov
View
255
Download
3
Embed Size (px)
DESCRIPTION
General mistakes often made by developers new to Erlang
Citation preview
Erlang data operation
caveats
FunBox
Илья Аверьянов
1. Deadlocks
Обращение к самому себе
%%% blacklist.erl
handle_call(get_all_blacklisted, _From, #st{all_blacklisted = AllBlacklisted} = St) ->
{reply, AllBlacklisted, St};...handle_call({is_blacklisted, Word}, _From, St) ->
AllBlacklisted = gen_server:call(blacklist, get_all_blacklisted),IsBlacklisted = lists:any(fun(W) -> W =:= Word end, AllBlacklisted),{reply, IsBlacklisted, St};
Взаимное обращение%%% processor.erl...handle_call({process_job, Job}, _From, St) ->
do_job(Job),gen_server:call(generator, {register_completion, Job}),{reply, true, St};
%%% generator.erl...handle_call(generate_job, _From, St) ->
Job = generate_job(),gen_server:call(generator, {process_job, Job}),{reply, true, St};
Бесконечный timeout
gen_server:call(Pid, Message, infinity)
gen_server:call(Pid, Message, 10000)
gen_server:call(Pid, Message)
Как найти?
erlang:system_info(procs)
2. Bottlenecks
2.1. Явные bottleneck-и
Медленные операции в gen_server
handle_call({calculate_pi, Digits}, _From, St) ->Pi = calculate_pi(Digits),{reply, Pi, St};
handle_call({get_new_files_from_bbs, Boss}, _From, St) ->Files = get_new_files_from_bbs(Boss), {reply, Files, St};
Лишнее копирование данных
Плохо
is_blacklisted(Word) ->AllBlacklisted = gen_server:call(BlackListPid, get_all_blacklisted),sets:is_element(Word, AllBlacklisted).
handle_call(get_all_blacklisted, _From, #st{all_blacklisted = AllBlacklisted} = St) ->
{reply, AllBlacklisted, St};
Хорошо
is_blacklisted(Word) ->AllBlacklisted = gen_server:call({is_blacklisted, Word}).
handle_call({is_blacklisted, Word}, _From, #st{all_blacklisted = AllBlacklisted} = St)
Result = sets:is_element(Word, AllBlacklisted).{reply, Result, St};
Документация!
● http://www.erlang.org/doc/efficiency_guide/processes.html
● Refc binaries (не копируются между процессами в рамках одной
виртуальной машины)
● Heap binaries (<= 64 bytes)
● ets и dets
2.2 Неявные bottleneck-и
Плохо
handle_cast(incr, St = #st{redis = Redis}) ->
spawn_link(fun() -> redis:qp(Redis, "INCR key") end).
St.
3. Лишнее копирование
См. 2.1.
Более хитрый пример
handle_deliver_sm(Pdu, {Pid, _}, #st{smsc_monitor_pid = SmscMonitorPid} = St) ->smsc_monitor:event(deliver_sm, SmscMonitorPid),event_counter:event(esme_client_deliver_sm),do_handle_deliver_sm(Pid, Pdu, St),{reply, noreply, St}.
handle_deliver_sm(Pdu, {Pid, _}, #st{smsc_monitor_pid = SmscMonitorPid} = St) ->smsc_monitor:event(deliver_sm, SmscMonitorPid),event_counter:event(esme_client_deliver_sm),spawn_link(fun() -> do_handle_deliver_sm(Pid, Pdu, St) end),{reply, noreply, St}.
handle_deliver_sm(Pdu, {Pid, _}, #st{smsc_monitor_pid = SmscMonitorPid} = St) ->smsc_monitor:event(deliver_sm, SmscMonitorPid),event_counter:event(esme_client_deliver_sm),spawn_link(fun() -> do_handle_deliver_sm(Pid, Pdu, St) end),{reply, noreply, St}.
handle_deliver_sm(Pdu, {Pid, _}, #st{smsc_monitor_pid = SmscMonitorPid} = St) ->smsc_monitor:event(deliver_sm, SmscMonitorPid),event_counter:event(esme_client_deliver_sm),LightSt = St#st{reqs = undefined},spawn_link(fun() -> do_handle_deliver_sm(Pid, Pdu, LightSt) end),{reply, noreply, St}.
Как бороться
● Передавать в процесс только необходимые ему данные (в рамках
функционального стиля)
● Не делать по возможности спаун линк, а использовать другой
gen_server с пулом воркеров к нему
3. Memory leaks
Локально
gen_server:cast(LocalPiCalcPid, {calculate_pi, Digits}).
На удаленной машине
gen_server:cast({PiCalcPid, remote@node}, {calculate_pi, Digits}).
Как найти и побороть
process_info(Pid),
process_info(Pid, memory)
4. IO
Плохо
case process_job(Job) of{ok, Res} ->
send_job_result(Res);{error, some_noncritical_frequent_error} ->
lager:error(“Error: some_noncritical_frequent_error”)end.
Хорошо
file:open(Path, [append, raw, {delayed_write, ?WRITE_BUFFER_SIZE,
?WRITE_BUFFER_MAX_DELAY}])
5. Недостаток ресурсов
● erl +P 1048576
● ulimit -n
● no swap!