Обновить
19
0
Odobenus Rosmarus @OdobenusRosmarus

Пользователь

Отправить сообщение
«Вы думаете лучшими специалистами в своем деле становятся талантливые и гениальные люди? Нет, быть лучшим — это возможность каждого нормального человека! И у тебя, Хаброжитель, эта возможность тоже есть!»

Видимо из контекста предполагается что среди хабражителей нет отличных специалистов. И даже талантливых людей…
Если вы верите поговорке, что терпение и труд, всё перетрут, попробуйте выдавить пасту из тюбика, а потом вдавить ее обратно (Ильф и Петров, если правильно помню)
10000, 10000, 100, 47 — это не входные параметры. Это константы в программе. Поэтому строго говоря оптимизатор имеет полное право сделать сверку выражений и достаточно умный оптимизатор в итоге будет иметь просто число 39.

Посмотрел, почему run2 получился немного медленнее чем run (хотя по смыслу это вроде то же самое).

После дизассемблирования beam файла оказалось, что loop1 и loop2 адресуются статически, типа
{move,{integer,10000},{x,0}}.
{move,{x,2},{y,0}}.
{call,3,{test,loop2,3}}. < == Вот оно
{gc_bif,'-',{f,0},1,[{y,0},{integer,1}],{x,2}}.
{move,{x,0},{x,1}}.
{move,{x,2},{x,0}}.
{call_last,2,{test,loop1,2},1}.

А в dotimes вызывается преданная ей функция, которая в свою очередь создает переменную-функцию.
Типа в dotimes:
{function,dotimes,3,14}.
{label,13}.
{func_info,{atom,test},{atom,dotimes},3}.
{label,14}.
{test,is_eq_exact,{f,15},[{x,0},{integer,0}]}.
{move,{x,2},{x,0}}.
return.
{label,15}.
{allocate_zero,2,3}.
{gc_bif,'-',{f,0},3,[{x,0},{integer,1}],{y,1}}.
{move,{x,2},{x,4}}.
{move,{x,1},{x,2}}.
{move,{x,4},{x,1}}.
{move,{x,2},{y,0}}.
{call_fun,2}. < == Вот вызов
{move,{y,0},{x,1}}.
{move,{x,0},{x,2}}.
{move,{y,1},{x,0}}.
{call_last,3,{test,dotimes,3},2}.

А это функция которая вызывается:

{function,'-run2/0-fun-1-',2,21}.

{make_fun2,{test,'-run2/0-fun-0-',3},2,29791076,1}.


То есть простыми словами — решение с dotimes создает дополнительно 10000 переменных типа функция, которые потом собираются garbage коллектором.

А я тестировал на R12B5.

Попробовал на R13B1 —
6> timer:tc(test,start,[]).
{19239320,39}
7> timer:tc(test,run,[]).
{7114840,39}
8> timer:tc(test,run2,[]).
{8048659,39}

На R12B5 — 2> timer:tc(test,start,[]).
{28226647,39}
3> timer:tc(test,run,[]).
{7789521,39}
4> timer:tc(test,run2,[]).
{8189215,39}

Другими словами, Ваш первый вариант при переходе с R12 на R13 ускорился почти на треть — с 28 сек до 19 сек. Однако…
А рекзультаты на функциях улучшились чуть-чуть с 7.7 и 8.1 до 7.1 и 8.0 сек…

на эрланге пробовали ниже по обсуждению. вроде как не быстрее получается.
Valgrind хорош, спору нет, но он не панацея. Нужно иметь полный code coverage при тестировании, чтобы его вывод имел смысл. Если ваши тесты не покрывают всего кода, (там к примеру обработки ошибок или редко встречающиеся условия), то valgrind будет просто не в курсе о том, что там может быть что-то с памятью.
То есть, как писал Дейкстра " Тестирование может доказать наличие ошибок, но никогда не докажет их отсутствие". Поэтому образно говоря в языках с встроенным управлением памяти надо постараться, чтобы слохопотать NullPointer, а в C надо очень стараться чтобы не схлопотать.
пузомерки (benchmarks) дают возможность представлять не только «кто шустрее», но «насколько шустрее».

К примеру у вас есть питоновская программа, которая реализует какую-то логику. Надо добавить числодробительный модуль. Можно написать на питоне, можно сделать вставку на C. Имеет смысл возиться с С? не имея представления какой может быть выигрыш — не ответишь.

задачи на арифметические выражения — вполне реальный класс задач. Навскидку — любая статобработка. Навскидку — raytracing… Автор вполне ясно объяснил свои намерения в статье, поэтому я считаю ваш упрёк не состоятелен.

PS про shootout уже несколько раз писали в обсуждении.
1) Скорее наоборот. С С++ мегаофигены пока не надо следить за памятью. Иначе рискуешь воткнуться в sigsegv.
2) ocaml и erlang очень разные языки, «окамли и эрланги» — непоятно по какому признаку вы их обьединили. По наличию gc? так в python и java он тоже есть. По «функциональности» языка? так ocaml позволяет писать не функционально и приведенный пример как раз написан императивно… Поясните пожалуйста вашу мысль.
то же на haskell

module Main where

loop1 :: Int -> Int -> Int
loop1 0 x = x
loop1 n x = loop1 (n-1) (loop2 10000 x n)
loop2 :: Int -> Int -> Int -> Int
loop2 0 r _ = r
loop2 j r i = loop2 (j-1) ((r + ( (i * j) `rem` 100)) `rem` 47) i

main = do
putStr «Result „
print (loop1 10000 0)

$ghc -O test.hs -o tesths
$time ./tesths

Result 39

real 0m7.442s
user 0m7.316s
sys 0m0.028s

7 c хвостиком (примерно полвосьмого) секунд

на той же машине лисп cmucl
(defun tst () (let (( r 0)) (dotimes (i 10000) (dotimes (j 10000) (setf r (mod (+ r (mod (* i j) 100)) 47) ) )) r))

* (compile-file «test.lisp»)
* (load «test»)
; Loading #p"/home/w/sandbox/test.x86f".
T
* (time (tst))
; Compiling LAMBDA NIL:
; Compiling Top-Level Form:

; Evaluation took:
; 10.62 seconds of real time
; 10.296644 seconds of user run time
; 0.032002 seconds of system run time
; 20,399,873,134 CPU cycles
; 0 page faults and
; 0 bytes consed.
;
39

То есть 10 сек
делаем так:

-module(test).
-export([start/0,run/0]).
start() ->
Seq = lists:seq(0, 10000),
lists:foldl(fun(I, R) -> lists:foldl(fun(J, R2) -> (R2 + (I * J) rem 100) rem 47 end, R, Seq) end, 0, Seq).

run() ->
loop1(10000,0).
loop1(0,X) -> X;
loop1(N,X) ->
X1 = loop2(10000,X,N),
loop1(N-1,X1).

loop2(0,X,_) ->X;
loop2(J,R2,I) ->
R = (R2 + (I * J) rem 100) rem 47,
loop2(J-1,R,I).

3> c(test,[native]).
{ok,test}
5> timer:tc(test,start,[]).
{28965824,39}
6> timer:tc(test,run,[]).
{7921692,39}
7>

То есть вашим вариантом на моей машине — 28 сек, переписаным — 8 сек.
кстати насчет ocaml:

let r = ref 0;;

let tstfunc x =
for i = 1 to x do
for j = 1 to x do
r := (!r + (i * j) mod 100) mod 47;
done;
done;;
tstfunc 10000;;
Printf.printf «Result %d\n» !r;;

и дальше
$ ocamlopt speedtest.ml -o sptest
$ time ./sptest
Result 39

real 0m6.364s
user 0m6.136s
sys 0m0.044s

6 секунд на amd 4000+
а почему не c(test,[native])?
Очень плохо, что Вы относитесь к шуткам как набору слов.

Кстати что это за гейзенберговское наблюдение? Если принцип неопределенности Гейзенберга то там «Гейзенберг» и «наблюдение» отдельные слова.
А как вы узнаёте что вы тот-же что и год назад? Человек все время в процессе обмена веществом с окружающей средой. Безо всякой телепортации.
а кто за тебя будет бэкапы делать? сам виноват
Да, она, просто модифицированный вариант, рассчитанный на компьютеры с малой памятью
en.wikipedia.org/wiki/Merge_sort раздел Merge sorting tape drives

Информация

В рейтинге
Не участвует
Откуда
Queensland, Австралия
Дата рождения
Зарегистрирован
Активность