Erlang бинарный в нижнем регистре производительности - PullRequest
0 голосов
/ 17 февраля 2019

Моя цель - повысить производительность двоичного преобразования только в ASCII в нижний регистр.Мне не нужны никакие языки, кроме английского.Я написал и сравнил несколько вариантов:

Двоичное понимание:

binary_comprehension(Binary) ->
    << <<if
             C >= $A andalso C =< $Z -> C - $A + $a;
             true -> C
         end >>
       || <<C>> <= Binary >>.

Понимание списка:

list_comprehension(Binary) ->
    L = binary_to_list(Binary),
    Lower =
        [if
             C >= $A andalso C =< $Z -> C - $A + $a;
             true -> C
         end || C <- L],
    list_to_binary(Lower).

И обычная строка: строчные буквы.

И удивительно, что списочное понимание превосходит все остальные:

1> timer:tc(fun() -> lists:foreach(fun(_) -> tolower:list_comprehension(<<"QWEQWEIQEKQHWKEHKQWHEKQHWKEQWEKHQWLKL">>) end, L100000) end).
{267603,ok}

2> timer:tc(fun() -> lists:foreach(fun(_) -> tolower:binary_comprehension(<<"QWEQWEIQEKQHWKEHKQWHEKQHWKEQWEKHQWLKL">>) end, L100000) end).
{324383,ok}

3> timer:tc(fun() -> lists:foreach(fun(_) -> string:lowercase(<<"QWEQWEIQEKQHWKEHKQWHEKQHWKEQWEKHQWLKL">>) end, L100000) end).
{319819,ok}

Есть идеи, почему преобразование двойного списка + понимание намного быстрее, чем просто двоичное преобразование?

Может быть, вы знаете более мощную оптимизацию?

Обновление:

Я также обнаружил, что версия строки со списком символов также быстрая:

string_lowercase(Binary) ->
    L = binary_to_list(Binary),
    Lower = string:lowercase(L),
    list_to_binary(Lower).

Запуск:

39> timer:tc(fun() -> lists:foreach(fun(_) -> tolower:string_to_lower(<<"QWEQWEIQEKQHWKEHKQWHEKQHWKEQWEKHQWLKL">>) end, L100000) end).
{277766,ok}

1 Ответ

0 голосов
/ 20 февраля 2019

Я сделал некоторую модификацию кода и изменил контрольный пример.Изменения в тесте не являются обязательными, но лично мне больше нравится этот способ:

-module(tolower).
-compile(export_all).

u2l(C) when C >= $A andalso C =< $Z -> C + 32;
u2l(C) -> C.

binary_comprehension(Binary) ->
  << << (u2l(C)) >> || <<C>> <= Binary >>.

list_comprehension(Binary) ->
  list_to_binary([u2l(C) || C <- binary_to_list(Binary)]).

list_recur(Binary) -> list_recur(binary_to_list(Binary), []).

list_recur([], Result) -> lists:reverse(Result);
list_recur([C | Tail], Result) when C >= $A andalso C =< $Z ->
  list_recur(Tail, [(C + 32) | Result]);
list_recur([C | Tail], Result) ->
  list_recur(Tail, [C | Result]).

string_to_lower(Binary) ->
  list_to_binary(string:lowercase(binary_to_list(Binary))).

test() ->
  L100000 = lists:seq(1, 100000),
  TL0 = <<"QWEQWEIQEKQHWKEHKQWHEKQHWKEQWEKHQWLKL">>,
  TL = binary:copy(TL0, 100000),
  {R0, _} = timer:tc(fun() -> lists:foreach(fun(_) -> tolower:binary_comprehension(TL0) end, L100000) end),
  {R1, _} = timer:tc(tolower, binary_comprehension, [TL]),
  {R2, _} = timer:tc(tolower, list_comprehension, [TL]),
  {R3, _} = timer:tc(tolower, list_recur, [TL]),
  {R4, _} = timer:tc(string, lowercase, [TL]),
  {R5, _} = timer:tc(tolower, string_to_lower, [TL]),
  io:format("~n1.binary_comprehension = ~10w~n2.binary_comprehension = ~10w~n3.  list_comprehension = ~10w~n4.          list_recur = ~10w~n5.           lowercase = ~10w~n6.     string_to_lower = ~10w~n", 
  [R0,R1,R2,R3,R4,R5]).

Оболочка Эрланга показывает, что прошедшее время не согласовано из-за параллельного характера системы.Но лучшее время для ожидаемого двоичного_компонента, как и ожидалось.

62> c(tolower).    
tolower.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,tolower}
63> l(tolower).    
{module,tolower}
64> tolower:test().

1.binary_comprehension =     109000
2.binary_comprehension =      94000
3.  list_comprehension =     312001
4.          list_recur =     344001
5.           lowercase =     469002
6.     string_to_lower =     218000
ok
65> tolower:test().

1.binary_comprehension =     140998
2.binary_comprehension =      93999
3.  list_comprehension =     327994
4.          list_recur =     296996
5.           lowercase =     155997
6.     string_to_lower =     280996
ok
66> tolower:test().

1.binary_comprehension =     124998
2.binary_comprehension =      93998
3.  list_comprehension =     327995
4.          list_recur =     296995
5.           lowercase =     452993
6.     string_to_lower =     202997
ok
67> tolower:test().

1.binary_comprehension =     125000
2.binary_comprehension =      94000
3.  list_comprehension =     312000
4.          list_recur =     282000
5.           lowercase =     171000
6.     string_to_lower =     266000
ok

Время в строке 5 отличается от времени в строке 6, поскольку при вызове строки: нижнего регистра / 1 с двоичным аргументом она обрабатывается как последовательность utf8.При вызове строки: нижний регистр / 1 со строковым аргументом исключает обработку utf8.Подробнее см. Код string.erl из OTP.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...