Сравнивали Haskell и C++, а сравнили jump и cmov

    Что самое смешное — <br> я собирал хаскель-код через LLVM-бекенд,<br> но при этом сравнивал с GCC


    В статье [ссылка] было заявлено, что производительность Haskell кода превзошла код на С++. Что сразу вызвало интерес, т.к. и то и другое может генерироваться LLVM компилятором, значит либо Наskell может давать больше хинтов компилятору, либо что-то не так с С++ реализацией. Далее мы разберём, как череда случайностей в действиях автора привела к неправильным выводам, которые описываются таблицей ниже (под катом).


    Предисловие


    Недавно на хабре появилась очередная статья от 0xd34df00d про оптимизацию хаскель кода. Сравнивается в таких случаях естественно с неоспоримым лидером в производительности — С/C++. Затем последовал разбор этой статьи от yleo о том какой асм код действительно лучше, и в чём кроется различие реализаций на разных ЯП (рекомендую к прочтению). Ещё раньше (около полутора месяцев назад), была опубликована предыдущая статья из серии "Хаскель vs С/C++", и я проделал похожий разбор, но вместо того чтобы опубликовать его на Хабр — увы, отложил в долгий ящик. Бурные дискуссии в комментариях на этой неделе побудили меня вернуться к прошлой теме. Сегодня я его наконец-то достал тот markdown документ из ящика, стряхнул пыль, дописал, и предоставляю его на ваше обозрение.


    Введение


    Напомню, что задача была про подсчёт расстояния Левенштейна [вики], и вот такие результаты были показаны в оригинальной статье:



    Реализация Отн. время
    С clang 9 103%
    С gcc 9.2 125%
    C++ gcc 9.2 163%
    C++ clang 9 323%

    Остановимся только на С/С++, т.к. другие бенчмарки были написаны, как заметили в комментариях, по методу "Пишем одной рукой, иногда закрывая надолго глаза". Они были добавлены как "бонус", и в рамках одной статьи их полноценно разобрать невозможно. Тем не менее, всё равно выражаю большой респект тому человеку, который в одиночку написал реализации больше, чем на 10-ке языков.


    Что подозрительно


    Во-первых, сразу бросается в глаза, что С++ версия гораздо медленнее Си, что, на самом деле, странно. Далее мы найдём, где потерялся zero-cost, а в другой части, надеюсь, покажем, как именно можно использовать мета-программирование С++, чтобы обходить Си. К тому же, на clang плюсовая версия оказалась медленнее в 3 (!) раза, хотя сишный код почти такой же по скорости как хаскель+ллвм, что ожидаемо, т.к. сlang и llvm — это один проект.


    Череда случайностей


    Если проследить, то дело было так: автор написал наивный код на плюсах и скомпилировал gcc и clang. Последний оказался в два раза медленнее, и автор его отбросил. Далее он проделал пару попыток оптимизировать код (подробнее ниже), но gcc было абсолютно фиолетово на эти изменения. После этого автор принялся за Хаскель и написал код, который делает примерно то же самое, что и плюсовый, за исключением неких, как окажется потом, важных перестановок инструкций.


    Дьявол кроется в деталях



    Нюанс std::min({...})


    Деталь номер один, которую заметил сам автор и множество людей в комментах, это использование std::min.


    Мне таки удалось воспроизвести ускорение в случае C++.
    Так, если вместо std::min({delCost, insCost, substCost})
    написать std::min(substCost, std::min(delCost, insCost)),
    то время работы под clang — уменьшается до 0.840 секунд
    Ура, быстрее всех остальных вариантов и почти хаскель.
    (Автор оригинальной статьи — 0xd34df00d)

    Смотрим на хаскель версию:


    A.unsafeWrite v1 (j + 1) $ min (substCost + substCostBase) $ 1 + min delCost insCost

    Как ни странно, тут как раз и есть два раза вызов функции min от двух аргументов и в том же порядке! (надеюсь, на таком уровне я понимаю хаскель правильно). Таким образом, автор, после исправления C++ версии, сам получает, что один llvm равен второму llvm. Собственно, это я ожидал с самого начала. К сожалению, предположение, что "Наskell может давать больше хинтов компилятору" не подтвердилось. Но судьба сложилась так, что изначально автор статьи "Быстрее чем С++; медленне, чем PHP" проверил эту замену только на гцц, а этому компилятору от этого ни холодно, ни жарко. Как видно в бенчмарке ниже:


    Компилятор Время оригнала Время исправленного (1)
    haskell/llvm 910ms -
    gcc 9.2 1211ms 1211ms
    clang 9 1915ms 852ms

    В реализации stdlib от gcc я не нашел каких-то специализаций для std::min в случае трёх элементов, хотя это не должно быть проблемой сделать на С++. На данный момент минимум там находится путём создания массива на стеке и его обхода алгоритмом std::min_element. В простых случаях, как уже было замечено в комментариях, разницы нет, и компилятор умеет сам выкидывать массив на стеке и генерировать оптимальный код:


    f(int, int, int):
            cmp     esi, edi
            mov     eax, edx
            cmovg   esi, edi
            cmp     esi, edx
            cmovle  eax, esi
            ret

    Примечание: cmov* = conditional move (условие: g — greater, le — less equal, и т.д.).


    Но что интересно, в случае, когда вовлечены указатели, это не так, и clang, в отличии от gcc, зачем-то кладёт данные на стек (туда указывает rsp регистр):


    fptr(int*, int*, int*):
            mov     eax, dword ptr [rdi]
            mov     dword ptr [rsp - 12], eax
            mov     ecx, dword ptr [rsi]
            mov     dword ptr [rsp - 8], ecx
            cmp     ecx, eax
            cmovle  eax, ecx
            mov     ecx, dword ptr [rdx]
            cmp     ecx, eax
            cmovle  eax, ecx
            ret

    Что косвенно объясняет, почему clang более чувствителен к этому изменению в исходном коде. Также в случае без initializer_list компилятор генерирует оптимальный asm уже при -O1, а с ним нужно вовлечь больше оптимизаций (-O2), чтобы добиться того же asm выхлопа. Таким образом, std::min(std::initializer_list) не совсем зеро-кост, тут создателям стд-либы, возможно, стоит подумать над перегрузками для некоторых эвристик.


    Вынесите s1[i]


    Деталь номер два, которую я обнаружил — это другая оптимизация из Хаскель, которую потеряли в С++.


    Да вынесите вы наконец уже s1[i] за рамки цикла! (я)

    Опять же, по роковой случайности, гцц на неё почти по барабану, а автор-то тестировал на гцц и, соответственно, забыл внести её в итоговое сравнение. Итак, это вынос s1[i] за тело цикла, который присутствовал уже на нулевой итерации хаскель кода


      let s1char = s1 `BS.index` i
      let go j | j == n = pure ()
        -- Тело цикла

    После применения этой оптимизации к коду на С++, мы получаем результаты быстрее, чем хаскель при сборке компилятором clang. Т.е. хаскель + llvm всё же добавляет какой-то оверхед, или ему не хватает -march=native. Самое забавное то, что, оставив строку с std::min без изменений, эта версия работает быстрее, чем если применить оба изменения! Значит, компилятор как-то не очень предсказуемо переставляет инструкции во время оптимизации, и некоторые решения "волей случая" оказываются быстрее, но это мы обсудим подробнее дальше.


    Компилятор Оригинал Исправленный (2) Оба исправления (3)
    haskell/llvm 910ms - -
    gcc 9.2 1211ms 1195ms 1195ms
    clang 9 1915ms 742ms 831ms

    Допилить напильником


    C++ вариант приведен для сравнения.
    Его можно оптимизировать ещё немного,
    но тогда это получится C с плюсовым main'ом, что не так интересно.
    (Автор оригинальной статьи)

    Как мы уже увидели, даже маленькие исправления могут быть абсолютно непредсказуемы в зависимости от компилятора, Поэтому, я всё же попробую чуть-чуть допилить код, потому что это не сложно:


      size_t lev_dist(const std::string &s1, const std::string &s2) {
        const auto m = s1.size();
        const auto n = s2.size();
    
        std::vector<int> v0;
        v0.resize(n + 1);
        std::iota(v0.begin(), v0.end(), 0);
        auto v1 = v0;
    
        for (size_t i = 0; i < m; ++i) {
          v1[0] = i + 1;
          char c1 = s1[i];
          for (size_t j = 0; j < n; ++j) {
            auto substCost = c1 == s2[j] ? v0[j] : (v0[j] + 1);
            v1[j + 1] = std::min(substCost, std::min(v0[j + 1], v1[j]) + 1);
          }
          std::swap(v0, v1);
        }
        return v0[n];
      }

    Тут я перешёл на 32-битный int в векторе и чуть упростил подсчёт результата — сначала ищем минимум, потом инкремент (что опять же уже присутствует в хаскель коде).


    Компилятор Оригинал Допиленный (3b)
    haskell/llvm 910ms -
    gcc 9.2 1210ms 831ms
    clang 9 1915ms 741ms

    Ура, теперь GCC тоже ускорился. Также я пробовал заменить счётчик j на указатели, что внезапно замедлило GCC. В то же время скорость clang осталась на своём максимуме.


    Осознаем результаты


    LLVM == LLVM


    Во-первых, мы получили, что если написать С++ код так же как Haskell код, то результат одинаковый при использовании clang-9. К тому же, на моём процессоре Skylake C++ версия оказывается даже быстрее. Код, который я бенчмаркал, будет находится на гитхабе, и можно будет проверить данный тезис на архитектуре Haswell, которую в основном использовал автор.


    Итак, приходим к выводу, что вместо сравнений языков, по факту проводилось сравнение компилятора GCC и LLVM.


    В оригинальной статье было детально разобрано, как на хаскеле написать код, заточенный под llvm, и обойтись без ffi, за что автору спасибо.


    GCC vs CLANG


    Во-вторых, до этого момента сложилось впечатление, что старичок gcc уже ни на что не годится. Поэтому, ставьте свою генту пересобираться clang-ом и читайте дальше.


    Отдельно отмечу, что в Си версии исходного кода, предоставленной автором, была директива компилятора, которая выбирает лучший код в зависимости от компилятора (#if !defined(__GNUC__) || defined(__llvm__)), что объясняет относительную разницу между Си реализациями и С++ реализациями, и соответственно, делать выводы о соотношении Си и С++ по приведённой автором таблице нельзя.


    clang не осиливает (либо не пытается) убрать ветвления. (Голос из зала)

    Попробуем понять, чем вызвана разница между GCC и LLVM. Для этого посмотрим, что там наворотил компилятор в asm. С gcc все более-менее ясно: один внутренний цикл, который на основе команд cmov* делает min (аналогично тому, что мы видели листинге выше). Я беру версию (3), это та, что с двумя исправлениями, и С++ выглядит так:


          for (size_t j = 0; j < n; ++j) {
            auto delCost = v0[j + 1] + 1;
            auto insCost = v1[j] + 1;
            auto substCost = c1 == s2[j] ? v0[j] : (v0[j] + 1);
            v1[j + 1] = std::min(substCost, std::min(delCost, insCost));
          }

    Ассемблер, который я ради не сильно знакомых с ним читателей решил прокомментировать, получается таким:


    .L42:
            inc     rcx  // j++
            mov     rdi, QWORD PTR [r12+rcx*8]  // загрузить v0[j+1]
            xor     edx, edx  // обнулить %edx
            cmp     r10b, BYTE PTR [r11-1+rcx]  // c1 == s2[j]
            setne   dl  // результат в последнем байте %rdx
            lea     r9, [rdi+1]  // стало v0[j+1] + 1
            add     rdx, QWORD PTR [r12-8+rcx*8]  // добавить v0[j]
            lea     rsi, [rax+1]  // %rax это v1[j]
            cmp     rdi, rax  // сравнить v0[j+1] и v1[j] до += 1
            mov     rax, r9
            cmovg   rax, rsi  // на основе сравнения выбрать результат после += 1
            cmp     rax, rdx  // меньшее %rax, %rdx
            cmovg   rax, rdx
            mov     QWORD PTR [r8+rcx*8], rax  // v1[j+1] = ...
            cmp     rbx, rcx  // loop
            jne     .L42

    Тут компилятор сам сделал оптимизацию, которая упоминалась в оригинальной статье — вместо загрузки v1[j] на каждой итерации мы передаем его через %rax.


    Что же касается LLVM, то тут какая-то лапша из переходов, которую полностью приводить не буду. Отмечу лишь для примера, что во одном из кусков во внутреннем цикле имеется конструкция, частично похожая на предыдущую:


    .LBB1_40:                               #   in Loop: Header=BB1_36 Depth=2
            mov     qword ptr [r14 + 8*rsi + 8], rax
            mov     rdx, qword ptr [rbx + 8*rsi + 16]
            inc     rdx
            inc     rax
            xor     ebp, ebp
            cmp     cl, byte ptr [r13 + rsi + 1]
            setne   bpl
            add     rbp, qword ptr [rbx + 8*rsi + 8]
            cmp     rax, rdx
            jg      .LBB1_41
            lea     rdi, [rsi + 2]
            cmp     rax, rbp
            jle     .LBB1_44
            jmp     .LBB1_43

    Примечание: jmp, j* = jump (условие: jg — greater, jle — less equal, и т.д.).


    Тоже загружаем данные из v0[j+1], v0[j], делаем cmp для s1[i], но потом у нас идёт набор из cmp + jump во всех вариациях. Оставшуюся лапшу так детально комментировать не буду, но вполне ожидаемо, что на однотипных данных (а это то, что делал автор) бранч предиктор рулит, и такой код работает быстрее, как заметили в комментариях. Давайте попробуем на других данных — двух случайных строках.


    Компилятор str a — str a, str a — str b random-random x2
    gcc 9.2 1190 ms 1190 ms
    clang 9 837 ms 1662 ms

    Как и ожидалось, в GCC не меняется результат ни на одну миллисекунду, а LLVM замедляется в 2 (!) раза, потому что бранч предиктор больше не работает.


    Итак, приходим к основному тезису статьи. По факту были сравнены две реализации алгоритмов: одна основана на условных переходах (jump), другая — на операциях условного копирования (cmov).
    Одна реализация работает лучше на однотипных данных, другая — на случайных.


    Естественно, компилятор не может знать заранее, какие данные будут у программы в реальной жизни. Для того, чтобы решить эту задачу, существует PGO (Кстати, тут языки с JIT могут заиграть новыми красками). Я проверил это в нашем случае и получил, что GCC после PGO выдает результат наравне с самой быстрой версией clang. Какие данные ближе к реальной задаче — это предмет отдельной дискуссии, которую мы оставим для последующих изысканий. Мне кажется, что хоть мы и будем в реальности сравнивать близкие строки, выбор в алгоритме между удалить/заменить/вставить всё же будет случайный, а ветка, когда не надо делать ничего, может быть обработана отдельной эвристикой.


    Выводы


    • Бенчмарки порождают холивары, а холивары — новые бенчмарки
    • Никакой дискриминации нет, LLVM генерирует хороший код для всех
    • Мало того, что GCC и LLVM дают разную скорость в зависимости от задачи, так еще и в зависимости от входных данных
    • Бенчмарки без четкого технического задания и полноценного набора входных тестовых данных не имеют смысла
    • Автору надо прикручивать обратно ffi. На самом деле нет, т.к. у него есть другой алгоритм, о чём, надеюсь, узнаем в других сериях
    • Не спешите бежать на новый язык или компилятор на основе бенчмарков в интернете

    Надеюсь, в следующей части будут рассмотрены детально эти два подхода и разобраны их плюсы и минусы в более реальных ситуациях, а так же предложены способы ускорения этого алгоритма.


    Где я мог обмануть


    Для полной корректности выводов надо было провести ещё и следующий эксперимент: Убирать оптимизации из Хаскель версии и проверять, стало ли оно медленнее, тогда можно было бы более полно проверить тезис об "умности" компиляторов и, в частности, о влиянии алиасинга. Но эту задачку я оставлю любителям ФП или Rust (Блин, я же сам в числе последних).


    P.S. Альтернативное решение


    Первый способ решить задачу — это проверить, решил ли её уже кто-то другой
    (Мой препод по матану)

    Напомню, что задача — это поиск редакционного расстояния, т.е. минимального числа вставок, удалений и замен символов, которые надо произвести, чтобы из строки s1 получить строку s2. Статья об этом уже была на хабре. В данной заметке мы рассмотрели способы оптимальной реализации алгоритма Вагнера-Фишера, который требует O(n*m) времени (два вложенных for). По ссылке выше есть ещё алгоритм Хиршберга, но он тоже работает за квадратичное время. Хотя всё же можно ускорить алгоритм, если нас не интересуют расстояния больше некоторого наперёд заданного k. Так же, есть трюк который должен позволить сделать векторизацию. Об этом писал автор обсуждаемой здесь статьи, но это уже тема для другой заметки.


    Спасибо LinearLeopard за исправление ошибки в этом абзаце.


    Приложение


    Методика бенчей


    • Флаги компилятора: -O3 -march=native -std=gnu++17.
    • Процессор: Intel i5-8250U (да, ноут)
    • ОС: Ubuntu 19.04 / Linux 5.0.0
    • Первый прогон для разгона турбо-буст, далее берём минимум из пяти подряд. Отклонения в рамках 1-2%.
    • Между запусками разных реализаций 1с прохлаждаемся (да, ноут)

    Добавлено: скрипты для ленивых


    Можете запустить всё то же самое на своем железе и сообщить общественности результат: ссылка на гитхаб.


    Добавлено: Результаты без -march=native


    По заявкам в комментариях, решил проверить влияние этого флага.


    Флаги -O3 -march=native -O3 -march=native -O3 -O3
    Компилятор Оригинал Допиленный (3b) Оригинал Допиленный (3b)
    haskell/llvm - - 910ms -
    gcc 9.2 1210ms 831ms 1191ms 791ms
    clang 9 1915ms 741ms 1924ms 807ms
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 142

      0

      Ух, моар «разборов».


      Что самое смешное — я собирал хаскель-код через LLVM-бекенд, но при этом сравнивал с gcc

      Какое милое КПДВ. А можно до конца цитировать плз?


      «Если сравнивать с clang (что вроде как логичнее), то всё становится ещё хуже для плюсов: почему-то на этой задаче clang проигрывает GCC в пару раз, и разница становится не 40%, а этак раза три. Впрочем, одна маленькая модификация C++-кода это поменяет.»


      либо Наskell может давать больше хинтов компилятору

      Вполне может. Алиасинга того же нет, да и вообще язык строже.


      Далее он проделал пару попыток оптимизировать код (подробнее ниже), но gcc было абсолютно фиолетово на эти изменения. После этого автор принялся за Хаскель и написал код, который делает примерно то же самое, что и плюсовый, за исключением неких, как окажется потом, важных перестановок инструкций.

      А далее (на самом деле в самом начале) автор даже упомянул, что кое-какие изменения в коде достаточно ускоряют clang.


      Как ни странно, тут как раз и есть два раза вызов функции min от двух аргументов и в том же порядке! (надеюсь, на таком уровне я понимаю хаскель правильно). Таким образом, автор, после исправления C++ версии, сам получает, что один llvm равен второму llvm.

      Это не исправление. Если вы таки посмотрите на дизасм std::min({a, b, c}), то увидите, что он разворачивается в ту же конструкцию, что и std::min(a, std::min(b, c)) с точностью до порядка аргументов — initializer list'ы призваны быть дешёвыми и реализуемыми без лишних аллокаций памяти.


      И да, это не «один llvm равен второму llvm». Тут очень важно, что делает фронтенд компилятора, и как именно он разворачивает синтаксический сахар. Например, у вас может возникнуть желание написать minimum [a, b, c] в хаскеле, но ввиду семантики списков это совсем неэквивалентная замена и куда ближе к std::vector vec { a, b, c }; std::min_element(vec.begin(), vec.end());


      Хотя, конечно, можно сказать, что компилятор обязан развернуть свёртку по списку статически известной длины в явную последовательность приложений соответствующей функции, и мне, если честно, немного печально, что ghc сегодня этого не делает (хотя это легко починить самому через RULES-прагму, но это уже немного читерство, ИМХО). Непонятно, правда, причём тут LLVM, если это дело фронтенда.


      К сожалению, предположение, что "Наskell может давать больше хинтов компилятору" не подтвердилось.

      См. выше, хинты кодгену тут ни при чём.


      На данный момент минимум там находится путём создания массива на стеке и его обхода алгоритмом std::min_element.

      В общем случае на результат работы компилятора C++ без оптимизаций лучше не смотреть, и std::min тут не исключение.


      Но что интересно, в случае, когда вовлечены указатели, это не так, и clang, в отличии от gcc, зачем-то кладёт данные на стек (туда указывает rsp регистр)

      Ну, то есть, clang не смог задешугарить предназначенный ровно для таких ситуаций сахар?


      Таким образом, std::min(std::initializer_list) не совсем зеро-кост, тут создателям стд-либы, возможно, стоит подумать над перегрузками для некоторых эвристик.

      Это (как ЕМНИП писал khim) скорее бага в clang.


      А перегрузку по длине списка у вас сделать не получится.


      ему не хватает -march=native

      Да, там нет -march=native. И то, что вы не указали к этому моменту, что вы не используете -march=native для хаскель-версии, но используете для плюсовых, это печально.


      Итак, приходим к выводу, что вместо сравнений языков, по факту проводилось сравнение компилятора GCC и LLVM.

      Так это и означает, ровно то, что хаскель имеет оверхед, сравнимый с C++, разве нет? Спасибо, что лишний раз доказали это за меня.


      Одна реализация работает лучше на однотипных данных, другая — на случайных.

      Только в данном случае данные совсем не случайные. Искомое расстояние почти всегда считается для очень близких данных.


      Не спешите бежать на новый язык или компилятор на основе бенчмарков в интернете

      А я бы побежал, раз оказывается, что от хаскеля в подобных задачах околонулевой оверхед, и различные реализации C++ между собой больше различаются, чем хаскель и быстрейшая реализация на плюсах.


      Убирать оптимизации из Хаскель версии и проверять, стало ли оно медленнее, тогда можно было бы более полно проверить тезис об "умности" компиляторов и, в частности, о влиянии алиасинга.

      Оптимизации кода на хаскеле, которые представлены в исходной статье, никак не связаны с алиасингом.




      Итого, что бы ты ни делал, тебя обвинят в читерстве или, как минимум, некорректных бенчмарках, потому что выиграли не С. Придерутся даже к тому, что ты не указал в методике измерений, что происходило с прерываниями и какая была другая нагрузка на машину. Если же в твоих бенчмарках выигрывает С, то можно делать что угодно (включая сравнение неэквивалентных алгоритмов, использование старых версий компилятора хаскеля, заточка под конкретную архитектуру кода на C с -march=native без указания этого, и так далее), и всё будет в порядке. А если ты типа как нашёл что-то, что выглядит и звучит как объяснение (не имеющее вообще никакого смысла, вроде упомянутого в комментах тезиса о том, что std::min({}) создаёт вектор), то ты, короче, молодец.


      Не, точно надо про метабенчмарки статью писать.

        +11

        Ох какой длинный комментарий.


        Какое милое КПДВ. А можно до конца цитировать плз?

        Вся цитата на КДПВ не влезла, а если серьезно, то вам не кажется что само предложение уже противоречивое: Код в три раза медленнее или после модификации работает так же, вы определитесь уже? И моя претензия что таблица не обновлена остается в силе :) Да и ваша цитата про модификацию далее по тексту. Вообщем имхо кдпв на то и кдпв чтобы быть провакационным, надеюсь вы не обижаетесь. Хм… возможно я ваши цитаты не обозначил что они именно ваши — исправлю.


        Вполне может. Алиасинга того же нет, да и вообще язык строже.

        В данном случае это не явно не проявилось. С удовольствием посмотрю на других примерах.


        Если вы таки посмотрите на дизасм

        Если вы таки прочтете мой пост внимательно…
        Вы сами видите что на ллвм min разворачивается в абсолютно разные инструкции в зависимости от окружающего кода. В хаскель коде ведь просто min от двух аргументов, так что вопрос про списки вообще не стоит. Более того вы там переставили порядок аргументов в версии через {} и без неё, что тоже важно. К тому же, на gcc можно тоже путем флагов или прагм (не точно) выбрать во что развернется min.


        march=native дает минимальный прирост, а иногда даже делает хуже я не помню точно, давно было. Тут никакой авто-векторизации нету, так что толку от него имхо мало.


        и различные реализации C++ между собой больше различаются, чем хаскель и быстрейшая реализация на плюсах.

        Ну у хаскеля вообще разброс в 10 раз. Но вы можете проверить как он будет себя вести при перестановках порядка сравнения и т.п. Я же предложил это в заключительной части. Я вангую что будет то же разброс в 2-3 раза в зависимости от комбинации данные + код что и у С++.


        По поводу всего остального. Я Хаскель упомянул только в первой части, и показал как именно эквивалентный 1в1 код на С++ дает примерно тот же результат на этой задаче. И почему мелочи важны. Далее речь про разные компиляторы и т.п. Кто выиграл не так интересно как почему, и тут ответ как раз кроется в cmov vs jump что и было показано.

          +2
          Код в три раза медленнее или после модификации работает так же, вы определитесь уже?

          Эм, а где там написано, что он работает так же?


          В данном случае это не явно не проявилось. С удовольствием посмотрю на других примерах.

          Их можно сконструировать искусственно. Не знаю, правда, насколько это честно.


          Вы сами видите что на ллвм min разворачивается в абсолютно разные инструкции в зависимости от окружающего кода.

          И это баг в llvm.


          Более того вы там переставили порядок аргументов в версии через {} и без неё, что тоже важно.

          Эм, ну да. Это ЕМНИП давало максимальный профит.


          march=native дает минимальный прирост, а иногда даже делает хуже я не помню точно, давно было. Тут никакой авто-векторизации нету, так что толку от него имхо мало.

          Судя по «давно было», на этой задаче вы не проверяли?


          Вон, в спецолимпиаде по wc -march=native даёт клангу двухкратный профит на моей машине (старый уже хазвелл) и трёхкратный на современных -lake'ах с AVX512. Хотя там тоже автовекторизацией в том же стиле, что руками, и не пахнет.


          Ну у хаскеля вообще разброс в 10 раз.

          Это как? И где вы вообще нашли хотя бы две актуальных реализации хаскеля? :)

            +5
            Эм, а где там написано, что он работает так же?

            Так у вас показано в таблице для Си — там 103%. Это и есть так же. Ну и у меня так же.


            Там нету ни одного векторного регистра в теле внутреннего цикла, вы мой асм смотрели или нет?)


            И это баг в llvm.

            Это не совсем баг, можно переставить ветвление в разном порядке, каждый будет лучше для определенного паттерна входных данных. Какой он как выбирает не понятно. В хаскеле же вы тоже юзаете эту багофичу. Не ужили я так плохо написал что не донес эту мысль :(


            Ну у хаскеля вообще разброс в 10 раз.

            Там у вас их куча на графиках. Мы точно про одну и ту же задачу говорим. Я не про wc если что.

              +2
              Так у вас показано в таблице для Си — там 103%. Это и есть так же. Ну и у меня так же.

              Ну да, а без этих оптимизаций заточек под компилятор — в три раза хуже.


              Там нету ни одного векторного регистра в теле внутреннего цикла, вы мой асм смотрели или нет?)

              Ну а почему тогда


              % clang++ -march=native -O3 main.cpp -o main
              % time ./main                               
              0
              20000
              ./main  0.70s user 0.00s system 99% cpu 0.698 total
              % clang++ -O3 main.cpp -o main       
              % time ./main                 
              0
              20000
              ./main  0.84s user 0.00s system 99% cpu 0.844 total

              даже на моей машине, где ещё меньше новых инструкций, чем у вас?


              Это не совсем баг, можно переставить ветвление в разном порядке, каждый будет лучше для определенного паттерна входных данных. Какой он как выбирает не понятно. В хаскеле же вы тоже юзаете эту багофичу. Не ужили я так плохо написал что не донес эту мысль :(

              Я про то, что он зачем-то спиллит регистры.


              Разная последовательность сравнений — это, конечно же, не баг, это конкретный выбор конкретного компилятора. И да, оптимизировать под это руками — такая себе идея, лучше брать PGO (как и вы написали, как и я написал полтора месяца назад), но PGO — это другое измерение этой задачи.


              Там у вас их куча на графиках.

              Я про разные реализации языка, а не алгоритма. Если от лёгкого шевеления исходного кода от становится быстрее на актуальном clang, но медленнее на актуальном gcc (и это то, что я наблюдал, и что указано в исходной статье), то это не оптимизация, а заточка исходника под конкретный компилятор, его решения и их связь (или её отсутствие) с входными данными.


              Безусловно, это осмысленно, если вы пишете что-то, что будет считаться неделю, и лишние 1-2-5% на конкретных данных на конкретной системе с конкретным компилятором вполне оправданы, но цель игры с такими вещами при сравнении разных языков от меня ускользает.

                –1

                Ну вот про эту разницу я и прокомментировал что дело в march=native. Можно в этом ковыряться еще но это дает процентов 10, по сравнению с разницей в два раза.


                заточек под компилятор

                Это была не заточка под компилятор а под данные. Что я продемонстрировал на примере разных данных. В чем смысл сравнения решений, если порядок "==" разный?

                  +3
                  Ну вот про эту разницу я и прокомментировал что дело в march=native. Можно в этом ковыряться еще но это дает процентов 10, по сравнению с разницей в два раза.

                  Ближе к 20 на моей машине, и это разница между «медленнее реализации на хаскеле» и «быстрее реализации на хаскеле».


                  Это была не заточка под компилятор а под данные.

                  Когда я с этим игрался, то порядок аргументов, дававший выигрыш для clang, ухудшал время работы при компиляции gcc.

                    0
                    Когда я с этим игрался, то порядок аргументов, дававший выигрыш для clang, ухудшал время работы при компиляции gcc.

                    Это всё равно заточка под данные. Просто разный компилятор по разному раскрывал min.


                    Upd: на самом деле там много разных мелочей, тот же +1 до или после сравнения. Например, последний вариант гцц который самый быстрый на "аааа" стороках, тоже проседает на рандомных данных, я думаю потому что там закрался бранчинг. Правильно отпрофайлить бранчинг сложно (см. статью про wc), я показал более подробнее основной момент.

                      +3

                      Ну вот учёт, как каждый из компиляторов это раскрывает, и есть по факту заточка под компилятор. Потому что вам придётся обмазывать код #if'ами на тему того, каким именно компилятором (и, возможно, какой именно версии) вы собираетесь.


                      Или можно просто взять PGO, наконец.

                        0

                        Но а какой смысл подгонять решение под компилятор, если на других данных оно замедлится в два раза? Тем более дальше вы говорите про пго.

                  0
                  Я про то, что он зачем-то спиллит регистры.

                  Кто гцц или шланг?

                    0

                    Шланг (в показанном вами примере с раскрытием std::min({ initializer list }) в более сложном контексте).

                      0

                      Мне кажется с march=native он там делает что то вроде анролла. Может в этом причина?

            +1
            Вполне может. Алиасинга того же нет, да и вообще язык строже.

            Но скорее всего с llvm так не поступает. Потому что вот например Rust
            попытался передавать где только может "restrict" и llvm сломалось,
            пришлось не выпендриваться: https://github.com/rust-lang/rust/issues/54878

              +1

              Да там бывает, еще интереснее, что после обновления ллвм в расте пропали проверки на выход за границы массива. Пофиксили вчера в 1.41.1.

                0

                Да, поэтому на практике NCG (родной ghc'шный генератор нативного кода) может творить чудеса, когда речь идёт о программировании в каких-то чисто функциональных парадигмах, а LLVM рулит и педалит, когда речь заходит о числодроблении.

                –2
                Непонятно, правда, причём тут LLVM, если это дело фронтенда.

                Простите, а что, при передаче в LLVM массив внезапно забывает, что у него константная длина? Почему и фронтенд, и бекенд не могут оба делать эту работу? Хотя раз она может и должна делатся бекендом, то зачем ее делать фронтенду?




                Вообще, все эти срачи про языки становятся надоедливыми. Я не понимаю, в чем их смысл. Начинать с идеоматического кода и потом обмазывать его всякими хаками по основам исследований, а что лучше в данный конкретный момент с данными конкретным компилятором и на данных конкретных данных — это сравнение хитрецы и навыков реализатора, но никак не языков. Сравнение языков будет, если вы дадите задачу реализовать сотне студентов, которые только что прочти "XXX для чайников" и сравните результат.


                Проблема в том, чтобы поставить эксперимент, потому что в такой постановке никто не мешает студенту засунуть в середину вычислений код для подсчета котиков в интернете, а введение формальных правил, типа "используйте то" или "не используйте это" — прямое нарушение условий эксперимента. С другой стороны, постановка условия в виде "реализуйте оптимальнейшим образом" обязательно приведет к тому, что часть особо умных прочитают еще что-нибудь по языку и просто спустятся поближе к уровню ассемблера, что и сделали авторы всех обсуждаемых статей. Так что сравнение языков — это будет сравнение наивных подходов на этих языках к реализации задач. Но не забывайте, что наивный подход в каждом языке разный — банальный (но не точный, просто для иллюстрации) пример — использование рекурсии в ФП языках и цикла в императивных. Наивный алгоритм будет диктоваться как задачей, так и общей философией языка. На этой уровне уже начинает влиять то, как именно была построено обучение в "XXX для чайников", так что идеального сравнения никогда не будет — всегда найдется к чему придраться.


                Если на языке нельзя, пользуясь приемами, описанными в вводной книжке, которую можно прочитать за вечер, написать близкий к идеальному код — это плохой язык. Все остальное — это уже демонстация опыта и глубоких пониманий конкретных реализаций, что, ИМХО, от языка никак не зависит.

                  +9
                  Если на языке нельзя, пользуясь приемами, описанными в вводной книжке, которую можно прочитать за вечер, написать близкий к идеальному код — это плохой язык.
                  Вот именно фразы, подобные этой, приводят меня в бешенство.

                  Да, если ты — ублюдочная девочка, борящаяся «за всё хорошоее и против всего плохого» (а в реальности твоих спонсоров волнует чтобы картинка хорошо по TV смотрелась и больше ничего) — то подобные высказывания нормальны.

                  Если же вы реально хотите чтобы мир стал лучше — то стоит задуматься. Любая сложная задача имеет простое, легкое для понимания — но неправильное решение.

                  Почему так? Потому что абстракции протекают и потому единственный способ сделать язык «хорошим» в вашем смысле — это сделать его настолько тупым и неэффективным, что это станет неважно. Ну там QuickBasic, Python, JScript, JavaScript в Netscape 2.0 и так далее.

                  Далее, проходит несколько лет, люди, пользующиеся этим вот всем, замечают что язык у них — как бы «хороший», но очень уж медленный и ресурсоёмкий. Его оснащают разного рода JIT'ами и примочками типа NumPy, язык становится «плохим»… и через несколько лет всё повторяется.

                  Пожалуйста — не будьте Гретым Туборгом, это ни к чему хорошему не придёт.
                    –2
                    Если же вы реально хотите чтобы мир стал лучше — то стоит задуматься.

                    Когда вы делаете шаг вперед — вы задумываетесь, какие мышцы бедра напрячь, какие силы приложить к каждой кости, какие углы должны быть между костями, учитываете массу надетой сейчас обуви и налипший на ней снег, и тысячу других мелочей, или все же просто берете, и шагаете?


                    Точно также и с языками — есть те, где вы вынуждены думать о всяких мелочах, которые вот ну совсем никак не должны влиять на конечный результат. О них должен думать компилятор — его затем и придумали. В этих вещах нет и не может быть никакой вариабельности — тупой, как пробка алгоритм, который верен сейчас, был верен сто лет назад и через сто тоже будет верным. Вы же предлагаете постоянно держать эту чушь в голове, делая за компилятор его работу.


                    А есть те, где это сделано за вас. Ну например. На заре зарождения языков программирования вы вынуждены были нумеровать строки программы, чтобы иметь возможность к ним перейти с помощью GOTO. Даже если вы его никогда не использовали. Затем появились языки, которые выкинули эту чушь из своей грамматики — за строками должен следить компилятор. Стало лучше? Удобнее? Какие-то абстракции протекли от автонумерации строк? Освободились ли головы программистов от необходимости следить, сколько строк занимает программа, искусственно нумеровать строки не через 1, а через 10, или 100, или любое другое число, чтобы иметь возможность вставить что-то в середину без переписывания всей программы?


                    Далее, проходит несколько лет, люди, пользующиеся этим вот всем, замечают что язык у них — как бы «хороший», но очень уж медленный и ресурсоёмкий.

                    А может просто они пытаются писать на нем то, что стоило бы писать на чем-то другом, более подходящем? Ну, знаете, вместо лома подметать веником. Но вместо этого вы пытаетесь заменить лом сначала связкой ломов, потом вилами, потом граблями, добавляете им зубцов, делаете из мягкого железа и в виде лент. Да, в итоге получился металлический веник, подметать удобнее, хотя дорогой паркет царапает, но теперь косплеить Фримена использовать его как лом уже нельзя.


                    Его оснащают разного рода JIT'ами и примочками типа NumPy, язык становится «плохим»…

                    Само по себе добавление JIT-а или использование библиотек, написанных на другом языке, не делает ваш язык "плохим". Плохим он становится, когда вы начинаете оглядываться, когда вы вынуждены оглядываться на все эти джиты и подобное. Утрированно, вот раньше вы могли расположить переменные в любом порядке, а теперь джиту нравится, только когда порядок вот такой и никакой другой. Причем еще и скачет непредсказуемо, если вы вдруг добавляете переменных, потому что там какой-нибудь хеш считается от списка переменных. И вот вместо того, чтобы думать над задачей, вы начинаете пляски, как вам расположить переменные таким образом, чтобы JIT или сборщик мусора или еще что-нибудь не сломалось. Вы можете сколько угодно знать и оправдывать такое положение вещей, с пеной у рта доказывать, что иначе сделать нельзя, так как абстракции текут, и вообще, программисты совсем обленились, должны же они хоть что-то делать, но это именно то, что делает язык "плохим", хоть ты тресни. И всего этого нет и не будет в книгах "для чайников".


                    Потому что абстракции протекают и потому единственный способ сделать язык «хорошим» в вашем смысле — это сделать его настолько тупым и неэффективным, что это станет неважно. Ну там QuickBasic, Python, JScript, JavaScript в Netscape 2.0 и так далее.

                    А мне казалось, что наиболее тупые языки (вроде ассемблера) как раз и являются самыми производительными. Ну или я не понял, что именно вы вкладываете с слово "тупой".


                    Знаете, где-то слышал:


                    Если ото всех вокруг воняет дерьмом — может, это ты сам обделался?

                    Если у вас слишком часто текут абстракции, то может проблема в языке с этими абстракциями? Иногда можно заменить протекшие абстракции менее текущими, иногда их вообще можно выкинуть.


                    Любая сложная задача имеет простое, легкое для понимания — но неправильное решение.

                    Как и всякое категоричное утверждение, это нуждается в доказательстве.

                      +2

                      Ну да, по-моему, в этих рассуждениях есть рациональное зерно. Чем больше производительности ты пытаешься выжать, тем ниже по технологическому стеку ты вынужден спускаться, и зачастую лучше просто использовать более подходящий язык, чем пытаться исправить дело с помощью компиляторозависимых трюков на менее подходящем. С другой стороны, эти статьи — это скорее познавательные курьёзы для демонстрации этих самых трюков, не нужно рассматривать их столь уж серьёзно.

                        +1
                        К сожалению в современных системы вы зачастую вы не можете «опуститься ниже по стеку». Даже если вы будете программировать в машинных кодах (а на большинстве современных систем ни на чём ниже вам программировать не дадут) — разница между jump и cmov никуда не денется.

                        Потому единственный способ в современных условиях сделать язык «хорошим» — это сделать его медленным и жрущим ресурсы. Зато всегда одинаково. Без «протекающих абстракций».

                        Это — действительно то, что вы рекомендуете делать?
                          +1
                          Да, но ты (утрированно) можешь сам вписать этот cmov через какую-нибудь asm директиву, а можешь пытаться шаманить над порядком переменных и операторов, добиваясь того, чтобы конкретный компилятор в конкретных условиях сделал то, что ты хочешь (а следующая версия того же компилятора все твоё сиюминутно достигнутое великолепие поломала). И в том, и в другом случае ты все равно будешь как минимум одним глазом глядеть в asm output, то есть фактически писать на ассемблере, только в первом случае — напрямую, а во втором — через… эхм… телемедицину.

                          P.S. Всякие SIMD интринсики у компиляторов не просто так наружу торчат, и в том же benchmarks game программы на совершенно разных языках совершенно не стесняются ими пользоваться «по месту».
                            0

                            В дополнение к вашему.


                            Я сейчас ваяю поддержку инлайн-ассемблера для хаскеля, и при написании асмокода для тестов смотрю в то, что генерирует компилятор плюсов для интринсиков в случае вроде такого: https://gcc.godbolt.org/z/WzxXr9, в связи с чем у меня два вопроса:


                            1. Если присмотреться, то mov %eax, %edx внутри цикла лишний. Как сделать, чтобы компилятор вынес его вне цикла?
                            2. Как не копипастить закомментированные строки, а сгенерировать их автоматически? Вложенные for с известным числом итераций и даже с #pragma unroll (или как там её) в массив генерирует менее оптимальный код.

                            Короче, единственный язык, на котором можно писать максимально производительный код — это язык ассемблера, а не С и не хаскель.


                            А вот генерировать язык ассемблера проще не из С.

                              0
                              В C поддержка inline assembly просто уже есть, хехе. По крайней мере, в gcc и clang :) Но вообще-то речь не столько именно об ассемблере, а, например, и о том, поймёт ли некий высокоуровневый компилятор, что некий объект в данном случае можно разместить на стеке, а не отдавать его под управление GC. Если в этом есть сомнения, а вопрос важный — лучше написать код на чем-то другом, где это отдаётся на откуп программисту.
                                0
                                В C поддержка inline assembly просто уже есть, хехе. По крайней мере, в gcc и clang :)

                                И асмовставки являются first-class citizens? Я могу написать функцию типа unroll/unrolls выше?


                                Но вообще-то речь не столько именно об ассемблере, а, например, и о том, поймёт ли некий высокоуровневый компилятор, что некий объект в данном случае можно разместить на стеке, а не отдавать его под управление GC. Если в этом есть сомнения, а вопрос важный — лучше написать код на чем-то другом, где это отдаётся на откуп программисту.

                                Этот же аргумент означает, что если есть вообще какие бы то ни было сомнения (про девиртуализацию, или про инлайнинг горы шаблонов, или про min со списком инициализации, например), то лучше писать код на чем-то другом, где это отдается на откуп программисту. И сомнения-то ведь эти подтверждаются практикой!


                                Короче, зачем писать на плюсах?

                                  0

                                  Ну вот поэтому иногда и приходится писать "на плюсах как на C", как в уже набившем оскомину примере с std::min и initializer_list. Никто же не отрицает, что такое бывает. Если вопрос важный, а место горячее, лучше уж гвоздями прибить.

                                    0
                                    Короче, зачем писать на плюсах?
                                    Зачем же, зачем и на любом другом языке программирования. На нём можно сделать максимально быстрый код (применив кодогенерацию если уж очень приспичит) — и при этом для написания остального кода вполне можно нанять достаточно программистов, чтобы судьба проекта не была под угрозой.
                                      +4
                                      На нём можно сделать максимально быстрый код (применив кодогенерацию если уж очень приспичит)

                                      Так для этого любой язык с FFI в C годится. Конкретный пример: было у меня предположение, что одна штука хорошо решается рагелом, ну я написал транслятор с предметного языка на рагел, плюс десяток строчек С++-клея для маршаллинга того, что сгенерённый рагелом код выплюнул, в мой код на угадайте-каком-языке. Плюсы там были нужны, чтобы использовать std::vector и не париться выделением-освобождением памяти руками, не более. Правда, оказалось, что рагела не хватает (ну или я там как минимум нужный мне контроль жадности не осилил, на некоторых входах он взрывался при конвертации NFA в DFA, да и не совсем регулярный язык это был, но даже на регулярном подмножестве всё было не очень), поэтому в итоге всё это выкинул и закодил самодельный велосипед с полунаркоманским недоjit'ом, но не суть.


                                      Тем не менее, зачем мне тут всё писать на С++? Зачем мне писать на С++ логику трансляции, оптимизатор предметного языка, статический анализатор предметного языка, обработчик результатов от сгенерённой стейтмашины, и так далее? Зачем мне писать на C++ работу с сетью, обвязки для принятой в компании шины сообщений (которые, к слову, на C++ были геморнее и сложнее, чем на хаскеле, несмотря на то, что плюсы — официальный язык, поддерживаемый чуваками, некоторые из которых есть в Комитете, а хаскель поддерживается полутора хасктивистами и ещё сотней сочувствующих)?


                                      А если начинать применять то, чем плюсы действительно хороши могут по сравнению с большинством остальных мейнстримных языков (компилтайм-метапрограммирование всякое), то до поры до времени это всё, конечно, весело и забавно (ну там, производную в компилтайме взять, или зазеркалить иерархию functor/applicative/monad в хане), но вскоре вы упираетесь во времена компиляции, в сообщения об ошибках, в ограничения метаязыка, и в то, что авторы «остального кода» не хотят в это всё вникать.


                                      Как, опять же, конкретный пример: на одной из прошлых работ было что-то вроде фреймворка для построения пайплайнов и написания блоков этих пайплайнов — ну как gstreamer, только для всякой лоу-летенси-финансовой ерунды. Да, там шаблоны везде, CRTP, ООП-наследование-полиморфизм-статически-виртуальные-функции в компилтайме через него, короче, всё как вы ожидаете от C++-профи, всё инлайнится и шустро работает, всё супер. Только вот


                                      1. Каждый TU, даже самый мелкий, компилируется от 3 до 10 минут, и жрёт при этом до 10 гигов памяти. 32-ядерный билдсервер с 64 гигами оперативки? Компилируй всё равно не больше чем в 6 потоков. Ну в 10, если охота испытать судьбу.
                                      2. Ошибки? Ну, во-первых, зачастую ждите от 2 до 9 минут, пока компилятор не прожуёт достаточно шаблонов, чтобы выплюнуть вам сообщение об ошибке. Во-вторых, его читаемость вы можете сами себе представить, про это я даже вспоминать не хочу.
                                      3. Написать свой блок для пайплайна? Без шансов, если вы не знаете достаточно хорошо плюсы.
                                      4. IDE? Какие IDE? CLion сжирал гигов 30, навигация тормозила, если работала, а почти всегда она не работала (CRTP и шаблоны везде передают привет).
                                      5. Начинало писаться это всё во времена gcc 6, и люди застряли на gcc 6, потому что gcc 6 разрешал некоторые вещи, которые последующие версии стали запрещать, и у меня заняло несколько недель вычистить примерно половину ошибок, чтобы более свежие компиляторы начали выдавать что-то осмысленное. До поддержки clang руки так и не дошли, кстати. Зато, пока оно компилируется, можно было на хабре в комментах потренировать пальцы, да. Ну или успеть прочитать пару-тройку новостей на N+1 за один цикл.
                                      6. Скорость работы отладочной сборки, скорость всяких asan'ов вы тоже можете себе представить. Весёлого исправления рантайм-ошибок. Впрочем, к счастью, всю эту ерунду писали люди, которые действительно более-менее знают своё дело, так что значимого числа ошибок в самом фреймворке не было.
                                      7. А, ну и этим толком никто не пользовался. Думается, если бы там был нормальный DSL без всей этой шаблонной наркомании, то пользователей было бы побольше, мир был бы покраше, а нервных клеток у всех бы осталось побольше. А так получился, знаете, такой продукт в себе, а не внутренний продукт внутри компании. И да, миграция на DSL была в планах, но всё это буйство красок схлопнулось до того, как был шанс его реализовать.

                                      при этом для написания остального кода вполне можно нанять достаточно программистов, чтобы судьба проекта не была под угрозой.

                                      Я что-то всё более скептически отношусь к тому, что на C++ можно нанимать достаточно программистов, которые могут не сломать код, и не потратят уйму времени на написание кода, которому более-менее как-то можно доверять.

                                        –1
                                        Тем не менее, зачем мне тут всё писать на С++?
                                        Вы хотите сказать, что если вы всё это напишите на Java или Python — будет лучше? Сомневаюсь: эти языки особо экономными никогда не были.

                                        Я что-то всё более скептически отношусь к тому, что на C++ можно нанимать достаточно программистов, которые могут не сломать код, и не потратят уйму времени на написание кода, которому более-менее как-то можно доверять.
                                        Это в том случае если вам нужно, чтобы продукт был надёжен и всегда работал. Но нынче это мало кому нужно.
                                          +2
                                          Вы хотите сказать, что если вы всё это напишите на Java или Python — будет лучше? Сомневаюсь: эти языки особо экономными никогда не были.

                                          Ну вы прям выбрали альтернативы!


                                          Впрочем, отдел датасотонистов на другой прошлой работе писал сплошь на плюсах, когда я пришёл туда примерно в 2014-м, но как-то постепенно все стали писать на питоне, и та команда, в которой был я, переходила на питон одной из последних в 2019-м, когда я оттуда уже увольнялся. И ничего, никто не умер, свеженабранные выпускники вузов на этом самом питоне могут смело, гм, творчески перерабатывать нейросетки из публикаций под tensorflow.


                                          Ну да, никто больше не сидит и не пишет самостоятельно какой-нибудь random forest на плюсах ковыряя байтики, чтобы всё в ОЗУ влезало и обучалось за единицы минут. Теперь апачи там везде со спарками бегают, бигдата, все дела. Но, опять же, никто не умер.


                                          Это в том случае если вам нужно, чтобы продукт был надёжен и всегда работал. Но нынче это мало кому нужно.

                                          А скорость тоже мало кому нужна примерно в таком же смысле.

                                            0
                                            Ну вы прям выбрали альтернативы!
                                            Дык эта. Что там в пятёрке ещё осталось? C#/Visual Basic.Net/JavaScript/PHP? Они не сильно лучше…

                                            А скорость тоже мало кому нужна примерно в таком же смысле.
                                            Ну не скажите. В том же tensorflow даже раскладку по испонительным блокам CPU прикидывают… разумеется не те, кто «творчески перерабатывают сетки», а те, кто пишут ядро этого самого tensorflow…
                                              +3
                                              Дык эта. Что там в пятёрке ещё осталось? C#/Visual Basic.Net/JavaScript/PHP? Они не сильно лучше…

                                              К счастью, мне никто не ставил условий «чтоб язык реализации был в топ N».


                                              Ну не скажите. В том же tensorflow даже раскладку по испонительным блокам CPU прикидывают… разумеется не те, кто «творчески перерабатывают сетки», а те, кто пишут ядро этого самого tensorflow…

                                              Именно. Но это надо именно тем, кто пишет ядро TF, потому что TF — это инструмент, и достаточно хороший, чтобы можно было им пользоваться вместо написания своих велосипедов на плюсах (или на питоне, или на матлабе).


                                              И таких инструментов становится всё больше, а потребности в умении (или возможности) писать жутко оптимизированный вычислительный код на местах — всё меньше. Поэтому в среднем потребности в условном С или плюсах (или высокопроизводительном хаскеле, в конце концов) тоже всё меньше, даже если рассматривать только то подмножество задач, где важна высокая производительность получающейся системы — просто появляются библиотеки, которые эту производительность обеспечивают, а для решения задач остаётся написать немного клея.

                                                0
                                                просто появляются библиотеки

                                                Из воздуха появляются, наверное :) Самозарождаются, как мыши в грязном белье у ван Гельмонта, никто их разработкой не занимается, все только «пишут немного клея на питончике», и все работает :)

                                                P.S. Сейчас ради интереса посмотрел — у того же TF почти 2.5K одних только прямых контрибуторов.
                                                  0

                                                  Это не отменяет того, что раньше для эффективного решения некоторого спектра задач знание плюсов было обязательно, а сейчас — нет.

                                                  0
                                                  К счастью, мне никто не ставил условий «чтоб язык реализации был в топ N».
                                                  Ну вам не ставили. А многим другим — ставят. Большинству причём. Как правило в компании есть вполне конечный набор языков, которые можно использовать (потому что HR знает как нанять разработчиков на этих языках). И расширить его непросто.

                                                  Но да, есть редкие исключения — там и Haskell можно и Scheme и даже Forth… но это редкость.

                                                  И таких инструментов становится всё больше, а потребности в умении (или возможности) писать жутко оптимизированный вычислительный код на местах — всё меньше.
                                                  Тут есть некоторое противоречие — если «таких инструментов становится всё больше», то, очевидно, для их разработки требуется всё больше людей.

                                                  Пользователей этого всего — да, ещё больше… но это уже другая история.
                                                    0
                                                    Тут есть некоторое противоречие — если «таких инструментов становится всё больше», то, очевидно, для их разработки требуется всё больше людей.

                                                    Неочевидно, это зависит от вашей модели.


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

                                                      0
                                                      Где-то и когда-то я это уже слышал. В школе ещё. Кажется Prolog должен был убить C++… или Lisp? Уже не помню. Помню что не срослось… Но Java точно должна была «закрыть тему». А ещё и C#, Python, PHP и ещё пара десятков других языков.

                                                      Собственно отсюда и рождается ограничение на языки. Про то, что специалисты по Cobol, Fortran, C++ или даже Java лет через 20-30 будут в наличии — очевидно.

                                                      А вот со всякими модными, но молодыми языками — вопрос очень сложный…
                                                        +1
                                                        Где-то и когда-то я это уже слышал.

                                                        Знаете эту историю про гуся, который думал, что его не зарубят никогда, потому что его не зарубили вчера и позавчера?

                                                          0
                                                          Знаю, да. Жил этот гусь у нас тут в лесопарке и его таки кормили регулярно и дожил он до глубокой старости…

                                                          Ой, вы не про этого гуся? А про того, которого на ферме не так далеко от того лесопарка откармливали? Ну так это другое дело!

                                                          </sarcasm>

                                                          Чтобы ваша аналогия с гусями чего-то стоила — нужно знать кто, где и как собирается «удушить» С++.

                                                          Вот в случае с взлётом и падением Pascal я могу всё описать легко. Turbo Pascal 1.0, в 1983м — это был офигительный прорыв, по сравнению с популярным тогда Microsoft Pascal — это был прорыв. Microsoft пытался с этим бороться (QucikBasic и QuickPascal, да) — но не смог.

                                                          Потому было принято решение Microsoft Pascal закорыть и кинуть все силы на Visual Studio. И это сработало: Delphi был популярен почти только на территории СНГ, а после того, как удалось сманить к себе ещё и разработчиков Borland C++… вопрос был закрыт.

                                                          Ахилессовой пятой Pascal оказалось то, что, фактически, популярность получил не Pascal как таковой, а один, конкретный (причём нестандартый) диалект…

                                                          А вот где вы видите кого-то, кто так же вот поступит с C++ (и, главное, почему это ему позволят сделать) — мне неясно.
                                                            +1
                                                            Ой, вы не про этого гуся? А про того, которого на ферме не так далеко от того лесопарка откармливали?

                                                            Да, вы-то про COBOL вспомнили. Ну да ладно, мне тоже хватит сарказмировать.


                                                            Заметьте, что вы обсуждаете несколько другой вопрос: умрут ли плюсы или не умрут. Не умрут, конечно, я с вами даже спорить не буду. Кобол вон тоже не умер.


                                                            Но, по крайней мере, лично мне важно не это. Важно то, насколько оправдан технологически (а не по велению эйчаров на галерах) выбор плюсов для новых проектов.


                                                            Ну и ещё лично мне важны некоторые субъективные эмоции при работе с кодом на плюсах. И в последнее время их всё меньше позитивных и всё больше негативных,


                                                            Но, конечно, плюсы — всё ещё мой самый любимый императивный язык. Наверное, это синдром утёнка (хотя моим первым языком был не C++) пополам со стокгольмским синдромом и loss aversion. Годы, потраченные в том или ином виде на задрачивание особенностей языка, иногда, как говорится, the hard way, жалко спускать в унитаз, а они будут спущены в унитаз, потому что этот опыт очень плохо трансферится.

                                            –1
                                            Как, опять же, конкретный пример: на одной из прошлых работ было что-то вроде...

                                            «вот был у нас проект на языке X, мы допустили типовую для этого языка ошибку Y и столкнулись с типовой проблемой Z, а вот если бы мы писали на языке A, то с проблемой Z мы бы точно не столкнулись (и давайте промолчим про проблему B)».

                                            Пусть X = java, Z = потребление оперативки. Или X = python, Z = низкое быстродействие. Или X = rust, Z = отсутствие наследования. Или X = haskel, Z = отсутствие человека, способного выразить логику программы в функциональном стиле. При этом для таких проблем обычно существуют типовые решения. Например, в расте вместо ООП советуют использовать ECS. А в доброй половине комбинаций проблема/яп типовым решением будет переписать на плюсы.

                                            И тут возникает резонный вопрос: почему для других языков нормально иметь типовые проблемы и типовые же методы их решения/предотвращения, а плюсам — нет?
                                              +4
                                              Или X = rust, Z = отсутствие наследования.

                                              Не могу назвать отсутствие наследования само по себе типовой проблемой.


                                              Но не суть. Какая типовая проблема была в данном случае у плюсов? Использование метапрограммирования? Как обойти эту проблему иначе в рамках данной задачи, оставаясь на плюсах или на сях?

                                                0
                                                Не могу назвать отсутствие наследования само по себе типовой проблемой.
                                                проблема возникает когда человек пытается свою ООП логику выразить в доступных расту терминах. И если делать это максимально в лоб, эмулируя наследование композицией, а не «мыслить иначе», получится очень много бойлерплейта и очень переусложненная архитектура.

                                                Примерно то же самое мы наблюдаем в плюсах когда человек пытается архитектуру приложения сделать полностью шаблонной, там, где отлично бы справились старые добрые виртуальные классы (интерфейс + реализация).
                                                  0
                                                  Примерно то же самое мы наблюдаем в плюсах когда человек пытается архитектуру приложения сделать полностью шаблонной

                                                  Ну вот в предыдущем вашем примере человек пытается свои привычные паттерны из более ООП-языков переложить на раст, и у него это не получается (так что, кстати, это не проблема раста). А какие привычные паттерны из каких других языков перекладываются тут?


                                                  там, где отлично бы справились старые добрые виртуальные классы (интерфейс + реализация).

                                                  Нет, не справились бы. Диспатчинг в рантайме — слишком медленно, когда вам важны наносекунды.

                                                    0
                                                    А какие привычные паттерны из каких других языков перекладываются тут?
                                                    в обоих случаях человек пытается решить задачу заведомо неоптимальным способом.
                                                    Нет, не справились бы. Диспатчинг в рантайме — слишком медленно, когда вам важны наносекунды.
                                                    LTO и девиртуализация тоже будут работать. А если уже и их будет не хватать, то там, где именно, можно и на шаблонах. А если вы боретесь за наносекунды в масштабах всего проекта, то у вас не такой уж и большой выбор языков программирования чтобы привередничать.
                                                      0
                                                      в обоих случаях человек пытается решить задачу заведомо неоптимальным способом.

                                                      Разве шаблоны и вот это всё не преподносятся в том числе как средство для эффективного решения подобных задач, требующих программирования во время компиляции?


                                                      LTO и девиртуализация тоже будут работать.

                                                      Девиртуализация там работала не очень хорошо по ряду причин, да и в любом случае, как там KanuTaH выше написал? «поймёт ли некий высокоуровневый компилятор, что некий объект в данном случае можно разместить на стеке, а не отдавать его под управление GC. Если в этом есть сомнения, а вопрос важный — лучше написать код на чем-то другом, где это отдаётся на откуп программисту.»?


                                                      Это ведь не только к GC относится, да?


                                                      А если вы боретесь за наносекунды в масштабах всего проекта, то у вас не такой уж и большой выбор языков программирования чтобы привередничать.

                                                      Какая разница, чем мне генерировать код на условном С (или LLVM IR, как я делал на другом проекте)?

                                                        0
                                                        Разве шаблоны и вот это всё не преподносятся в том числе как средство для эффективного решения подобных задач, требующих программирования во время компиляции?
                                                        давайте вернемся чуть-чуть назад, к моему комментарию:
                                                        Примерно то же самое мы наблюдаем в плюсах когда человек пытается архитектуру приложения сделать полностью шаблонной, там, где отлично бы справились старые добрые виртуальные классы
                                                        Я говорил об общей архитектуре приложения. Когда мы начинаем шаблонизировать все каркассные объекты в программе, хедеры начинают сильно зависеть друг от друга, а время компиляции TU, их использующих, начинает взрываться. Отдельные горячие участки примерно всегда локальны, выносимы в отдельные же TU, и как бы вы в них не извращались с шаблонами, это будет усложнение лишь одного TU. А теперь вернемся к:
                                                        лучше написать код на чем-то другом, где это отдаётся на откуп программисту
                                                        вот это как раз относится скорее к отдельным TU, реализующим те самые горячие участки
                                                          0
                                                          Когда мы начинаем шаблонизировать все каркассные объекты в программе, хедеры начинают сильно зависеть друг от друга, а время компиляции TU, их использующих, начинает взрываться.

                                                          Эм, ну да. Но если нет других способов добиться той же производительности без кодогенерации, то является ли это проблемой?


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

                                                          Не всегда. Если у вас весь пайплайн перекладывает байтики из входа драйвера сетевой карты в выход драйвера сетевой карты, то он весь горячий. И если вы пишете блок, как-то эти байтики преобразующий, то этот блок должен знать про своих соседей, чтобы аккуратно класть им куда надо результаты своих преобразований, чтобы избежать виртуальных вызовов и прочих индирекшонов.

                                                +2
                                                Или X = rust, Z = отсутствие наследования.

                                                А вы можете привести пример, когда использование наследования прям-таки необходимо? Потому что мне на ум приходит только GUI.

                                                0
                                                поэтому в итоге всё это выкинул и закодил самодельный велосипед с полунаркоманским недоjit'ом, но не суть.

                                                Вот про это я бы почитал. Не планируете писать статью?

                                                  0

                                                  Вряд ли получится. То было года три назад, доступа к тем исходникам я больше не имею (так как ушёл с той работы), да и если бы имел, то не уверен, что имел бы право рассказывать с достаточной степенью детализации.

                                          0

                                          Анроллы можно делать в С++, я не знаю где они есть в таком же виде ещё. Теперь у вас тоже есть, это здорово. Интринзики это все же уровень выше чем асм и их часто хватает.
                                          А по-поводу mov, дает ли это измеримую разницу?

                                            +1
                                            Анроллы можно делать в С++, я не знаю где они есть в таком же виде ещё.

                                            То есть, вы можете написать функцию, которая примет значения i от 1 до 8 и шаблон вставки вроде


                                              vmovdqa ${(i - 1) * 0x10}(%rdi), %xmm${i}

                                            и сгенерирует последовательность


                                              vmovdqa 0(%rdi), %xmm1
                                              vmovdqa 0x10(%rdi), %xmm2
                                              vmovdqa 0x20(%rdi), %xmm3
                                              ...
                                              vmovdqa 0x70(%rdi), %xmm8

                                            которая может использоваться внутри асмовставки?


                                            Можно пример?


                                            А по-поводу mov, дает ли это измеримую разницу?

                                            Я ещё не бенчмаркал. Но с точки зрения контроля это неважно.

                                              0

                                              А так нет, я думал вы про интринзик функции как в примере на си.

                                    0
                                    Когда вы делаете шаг вперед — вы задумываетесь, какие мышцы бедра напрячь, какие силы приложить к каждой кости, какие углы должны быть между костями, учитываете массу надетой сейчас обуви и налипший на ней снег, и тысячу других мелочей,
                                    Нет — и именно поэтому я перемещаюсь несколько медленнее, чем, скажем, Усэ́йн Болт.

                                    или все же просто берете, и шагаете?
                                    Всё зависит, как мы видим, от того, кто куда идёт. И зачем.

                                    Вы же предлагаете постоянно держать эту чушь в голове, делая за компилятор его работу.
                                    Я предлагаю? Нет. Я просто констатирую факт — вы можете этим заниматься. Или не заниматься. Разница будет примерно раз в 5-10. Как и в случае с простым шагом (метр-полтора в секунду или около того) и забегом рекордсмена (10 метров секунду или около того).

                                    На заре зарождения языков программирования вы вынуждены были нумеровать строки программы, чтобы иметь возможность к ним перейти с помощью GOTO.
                                    Серьёзно? Вот смотрю я на Fortran II 58го года — и чёт не вижу я таких требований. Потому смысл дальнейшей тирады, извините, от меня успользает.

                                    Обязательная нумерация строк в Basic для мини-компьютеров появилась для удобства — и действительно, если у вас нет приличного экранного редактора — это удобнее, чем попытка рассчитать на какой строке у вас там что находится.

                                    Когда текстовый редактор совместили с компилятором (Turbo Pascal 1.0), то стало понятно, что «есть решение получше».

                                    А вот в случае с выбором между jump и cmov… нельзя сказать что будет лучше, если вы не знаете с какими данными собрались работать.

                                    Само по себе добавление JIT-а или использование библиотек, написанных на другом языке, не делает ваш язык «плохим».
                                    Вы идиот? Или играете оного на TV? JIT — это протекающая абстракция. Библиотека, написанная на другом, гораздо более быстром языке — это тоже протекающая абстракция. Да даже банальный кеш процессора — это ещё одна протекающая абстракция.

                                    Как только вы вносите в вашу систему протекающую абстракцию — вы тут же теряете ваше свойство «хорошести»:
                                    Если на языке нельзя, пользуясь приемами, описанными в вводной книжке, которую можно прочитать за вечер, написать близкий к идеальному код — это плохой язык.
                                    Извините.

                                    А мне казалось, что наиболее тупые языки (вроде ассемблера) как раз и являются самыми производительными.
                                    Это вам только так казалось. Программа 20-летней (или, ещё лучше, 50-летней) давности на ассемблере будет работать сильно медленнее, чем программа той же давности, написанная на C или Fortran. Потому что ассмеблер — он ни разу не исключение, каким вы хотите его представить. Он тоже развивается — и тоже примерно так же, как все остальные языки.

                                    Ну или я не понял, что именно вы вкладываете с слово «тупой».
                                    Да всё вы понимаете. «Тупой» для ассмеблера — это без всяких movnti/prefetch2 и movaps/movdqu. И он таки медленее, чем более сложный ассемблер где все эти штуки имеются.

                                    Если у вас слишком часто текут абстракции, то может проблема в языке с этими абстракциями? Иногда можно заменить протекшие абстракции менее текущими, иногда их вообще можно выкинуть.
                                    Всё может быть. Но вот мы тут с вами переписываемся на сайте с названием Хабр и вы тут толкаете речи в защиту «хорошего языка» под названием ассмеблер. Ну и где ваш хороший браузер, написанный на этом хорошем языке? Вы же им пользуетесь, правда?

                                    Так что… или ссылку — или, извините, вы таки Гретый Туборг.
                                      +1
                                      Нет — и именно поэтому я перемещаюсь несколько медленнее, чем, скажем, Усэ́йн Болт.

                                      А живет он, наверное на стадионе и межкомнатные двери у него шириной с ворота самолетного ангара — с таким шагом нужно много места. Давайте не будем смешивать то самое оглядывание на JIT, попытку доказать, чей язык круче и решение повседневных задач.


                                      Всё зависит, как мы видим, от того, кто куда идёт. И зачем.

                                      Пока что в вашем примере я вижу одного тюнингованного человека для выполнения работки раз в… 1-3 года? Болид формулы 1 тоже один заезд ездит. Потом его выкидывают. Вы же, я надеюсь, пишите свои приложения несколько на иных принципах.


                                      Разница будет примерно раз в 5-10. Как и в случае с простым шагом (метр-полтора в секунду или около того) и забегом рекордсмена (10 метров секунду или около того).

                                      Но 100 метрах. На 1 километре разница тоже будет такая же, только участники местами поменяются. Все как я и говорил в самом начале — заточились на входные данные, на особенности железа, добавили мелких хаков, хотя задача была дойти из точки А в точку Б.


                                      Вот смотрю я на Fortran II 58го года — и чёт не вижу я таких требований

                                      А дальше в Basic увидели. Или вы зарей считаете только самый-самый первый язык программирования? А что тогда так поздно — википедия сообщает, что можно еще до 19 века начинать отсчет. На английской первый год другой, если вдруг русской не доверяете, но тоже до 1900 года.


                                      Обязательная нумерация строк в Basic для мини-компьютеров появилась для удобства — и действительно, если у вас нет приличного экранного редактора — это удобнее, чем попытка рассчитать на какой строке у вас там что находится.

                                      И правильно — расчетом должен заниматься компьютер. Для этого в более "хороших" языках придумали метки.


                                      А вот в случае с выбором между jump и cmov… нельзя сказать что будет лучше, если вы не знаете с какими данными собрались работать

                                      А я где-то утверждал обратное? Другое дело, что вы должны быть способны предсказать, что если вы используете эту конструкцию, то будет jump, а если эту — то cmov, а при использовании третьей вы сознательно отдаете решение на откуп компилятору. При этом, если от незначительного изменения входной программы результат меняется сильно (по аналогии с вычислением хеша), и это никак не отмечено явно, то такой язык "плохой". Вместо того, чтобы думать над алгоритмом вы вынуждены думать о побочных эффектах.


                                      Вот на примере данный статьи у одного человека замена min({a, b, c}) на min(a, min(b, c)) приводит к сильным изменениям, а у другого нет, на одном компиляторе приводит, а на другом нет. Т.е. имеем вычислительную нестабильность не только от смены представления одного и того же алгоритма, но даже от версии компилятора/реализации стандартной библиотеки!


                                      Как только вы вносите в вашу систему протекающую абстракцию — вы тут же теряете ваше свойство «хорошести»:

                                      Я никаких свойств хорошести не приводил. Я их не знаю. У нас не бинарная логика "хороший — плохой". Я указал лишь факторы, делающие язык "плохим". Опять же, не в абсолютном смысле, а только по сравнению с другими языками (но это, надеюсь, и так понятно).


                                      Это вам только так казалось. Программа 20-летней (или, ещё лучше, 50-летней) давности на ассемблере будет работать сильно медленнее, чем программа той же давности, написанная на C или Fortran. Потому что ассмеблер — он ни разу не исключение, каким вы хотите его представить. Он тоже развивается — и тоже примерно так же, как все остальные языки.

                                      Да неужели? Программы на С или фортране, наверное, имеют самомодифицирующийся код и при запуске на новых процессорах сами себя перепишут под новые инструкции, а на тупом ассемблере не догадались так написать. Гм.


                                      Вопросы же переносимости давайте оставим за кадром, мы не о них говорим


                                      Хабр и вы тут толкаете речи в защиту «хорошего языка» под названием ассмеблер.

                                      Если вы все же перечитаете мой комментарий, то вряд ли найдете там защиту хоть каких-то языков, а тем более определение каких-то языков в "хорошие".


                                      Да всё вы понимаете. «Тупой» для ассмеблера — это без всяких movnti/prefetch2 и movaps/movdqu. И он таки медленее, чем более сложный ассемблер где все эти штуки имеются.

                                      Ассемблер — это просто язык для записи опкодов. Добавление опкодов не делает сложнее язык, лишь процессор, их выполняющий. Усложнением языка будет добавление в него макросов.


                                      Аналогией вашему высказыванию будет, что Си, поддерживающий в идентификаторах Юникод, сложнее, как язык, чем Си, их не поддерживающий.




                                      И, наконец, последнее.


                                      Вы идиот? Или играете оного на TV?
                                      Но вот мы тут с вами переписываемся на сайте с названием Хабр

                                      Именно что Хабр, а не базар. Поэтому у вашего комментарий, на который я отвечаю, минус от меня. Переходить на личности с оскорблениями… плохо

                                        –1
                                        Как только вы вносите в вашу систему протекающую абстракцию — вы тут же теряете ваше свойство «хорошести»:
                                        Я никаких свойств хорошести не приводил. Я их не знаю. У нас не бинарная логика «хороший — плохой». Я указал лишь факторы, делающие язык «плохим».
                                        То есть у вас язык может быть одновременно и плохим и хорошим? Извините — но я не настолько гуманитарно одарён.

                                        Да неужели? Программы на С или фортране, наверное, имеют самомодифицирующийся код и при запуске на новых процессорах сами себя перепишут под новые инструкции, а на тупом ассемблере не догадались так написать. Гм.
                                        Нет, программы на C всего лишь могу изменить своё поведение (и существенно так изменить), если их перекомпилировать. Программы на ассемблере — нет.

                                        Но я боюсь если вам даже это нужно разжёвывать, то остальная дискуссия большого смысла не имеет.

                                        Именно что Хабр, а не базар. Поэтому у вашего комментарий, на который я отвечаю, минус от меня. Переходить на личности с оскорблениями… плохо
                                        Возможно. Но изображать из себя дебильную девочку, не умеющую в логику — ещё хуже. Да, я знаю: для того, чтобы заниматься политикой нужно уметь в двоемыслие. Но вот ракету там или ядреный реактор так уже не сделать — физика в двоемыслие не умеет.

                                        А Хабр — это скорее о ракетах, чем о том, как обвести толпу вокруг пальца и получит за это денег в свой карман…
                                          0
                                          То есть у вас язык может быть одновременно и плохим и хорошим? Извините — но я не настолько гуманитарно одарён.

                                          Это из чего вы такой вывод сделали?! В небинарной логике хорошо != !плохо, из чего не следует, что хорошо = плохо. Хотя, вот как ни странно, некоторые качества могут быть одновременно хорошими и плохими. Возьмем шаблоны C++. Они Тьюринг-полны — это круто, можно выразить что угодно. Они Тьюринг-полны — это кошмар, как их отлаживать? На сегодняшний день даже интерпретатора шаблонов нет! Мало того, код шаблонов обычно никто не комментирует, что хотя бы изредка делают с обычным кодом. Вопрос даже шире — их в общем случае невозможно скомпилировать из-за проблемы останова.


                                          Нет, программы на C всего лишь могу изменить своё поведение (и существенно так изменить), если их перекомпилировать. Программы на ассемблере — нет.

                                          Кто ж с этим спорит. Для этого в C и вводились абстракции. Но это как раз вопрос переносимости на другие процессоры и архитектуры. И не всегда эти самые существенные изменения будут в лучшую сторону, кстати. А если вы будите компилировать новыми компиляторами под старые процессоры, то вы хоть извернитесь, новых команд в выхлопе не получите. Странно, что вам этого не понятно. Поэтому возвращаю вам ваше замечание про логику.

                                            0
                                            А если вы будите компилировать новыми компиляторами под старые процессоры, то вы хоть извернитесь, новых команд в выхлопе не получите.

                                            Да, но новый компилятор может лучше оптимизировать код. Например, заменить деление на 3 на сдвиг и умножение.

                                  +4
                                  Вообще, все эти срачи про языки становятся надоедливыми.

                                  Именно.


                                  Моя цель — показать, какие изменения как влияют на хаскель-код. C или плюсы меня интересуют исключительно как некоторый бейзлайн, на которых относительно просто реализовать относительно оптимальный код (по крайней мере, для задач данного объёма). Если при этом оказывается, что реализация на хаскеле с тем же алгоритмом оказывается быстрее реализации на С с тем же алгоритмом — что ж, я не стесняюсь и пишу про это.


                                  Правда, оказывается, что кого-то это задевает, да настолько, что начинаются (совершенно простительные для бенчмарков в пользу С, конечно) вещи из последнего написанного мной абзаца. Да и вообще, посмотрите на этот тред — кому-то так не понравилось, что я пишу, что человек решил пройтись почти по всем моим комментам, включая чисто фактологические или упоминания результатов экспериментов.


                                  Короче, не понимаю, почему вы эту часть комментария адресуете мне, а не авторам статей, где происходит вышеупомянутый цирк.

                                    +3

                                    Я же делаю тоже самое, показал как микро изменения влияют на код на С++. Плюс почему и как это зависит от данных.

                                +1
                                Результат не самом деле великолепен.
                                Не важно на каком языке вы пишите. Важно какой компилятор вы используете.
                                То есть все языки по сути уравниваются. Классическое Нормально делай — нормально будет во всей красе.

                                И зачем продираться через муки С++, если можно не писать на нем и получать такую же производительность?

                                Осталось только уравнять компиляторы и вообще хорошо будет. Задачка сложная, но выглядит реально. И пиши вообще на чем удобнее. Все языки равны по производительности будут.
                                  0

                                  Во-первых не совсем на любом, но все что компилируется в натив через ллвм должно выдават то же самое. Тут ни ГЦ не будет, ни каких то интринзиков. Довольно простой код.

                                    0

                                    Чтобы тут ГЦ не было в языке с ГЦ, фронтенд этого языка таки должен постараться, независимо от LLVM.

                                      0

                                      А откуда ему взяться? как я знаю чары и инты тривиально копируется на всех языках, т.е. не объекты. Массив создаётся один раз в начале функции.

                                        0

                                        Только в хаскеле любой lifted-тип (Int, Char, что угодно, что вы встретите почти в любой программе на хаскеле) — заодно и boxed-тип, то есть, выделяется в куче, требует GC, и так далее. И только если компилятор может доказать, что это делать не обязательно (за счёт strictness analysis, как правило), тогда он сможет убрать выделения памяти и GC.


                                        Хорошая иллюстрация одного из моих тезисов выше.

                                          0

                                          Значит хаскель молодец, а я ошибся когда экстраполировал джаву.

                                      +1
                                      Это уже гораздо больше чем один С++.

                                      Простой это понятно. Сложный даже сравнивать бессмысленно. Там результаты могут оказаться вообще любыми. И споры будут бесконечны.
                                        0

                                        Надо рассматривать всесторонне. Так-то в этом коде никаких ужасов С++ нету.

                                          +3
                                          В этом нет. Но возможность писать на неком подмножестве языков код аналогичный по производительности С++ это гиганский плюс. Путь даже при этом придется ограничится подмножеством возможностей этих языков.

                                          Hot path пишем аккуратно и получается очень быстро, а остальное разворачиваемся и на том же языке пишем удобно. Никаких минусов межязыкового взаимодействия. Никаких ужасов плюсов. Красота же.
                                            0

                                            В идеале да, но пока всего один простой пример горячего кода. Я не утверждаю что дргуие получатся или нет. Скоро нам расскажут как симды подключить и наладить компайл тайм полиморфизм, и уже какая то часть сценариев покрыта.

                                              0
                                              Никаких минусов межязыкового взаимодействия. Никаких ужасов плюсов
                                              а если не пугаться плюсов то вообще красота же?
                                                +1

                                                А если не пугаться плюсов, то условный хаскель (или окамл, неважно) вас точно не испугает.

                                                  +1
                                                  Плюсы порождают сложноуловимые ошибки в ранатйме. И на них сложнее (чем на любом другом современном языке) писать типовой код.

                                                  И зачем писать на плюсах? Скорость это был непробиваемый агрумент. Но он начинает уходить. Все эти ABI и сопутствующая тормознутость стандартной библиотеки очень способсвуют.
                                                  И он слишком сложный. Я так и не придумал как культурно объяснить студенту почему в плюсах нет map.contains и надо помнить наизусть что надо писать вот так. А не как очевидно. И море подобных мест.

                                                  PS: Я учился писать по книжке Страуструпа. И за код на С++ получал деньги.
                                                    0
                                                    Все эти ABI...
                                                    скажем, многие из-за ABI на плюсах и пишут. Точнее, не уходят с плюсов благодаря возможности поддерживать старые кодобазы
                                                    И на них сложнее (чем на любом другом современном языке) писать типовой код.
                                                    проблемы с плюсами обычно начинаются когда на них пишут уже не типовой код.
                                                    И он слишком сложный. Я так и не придумал как культурно объяснить студенту почему в плюсах нет map.contains и надо помнить наизусть что надо писать вот так. А не как очевидно. И море подобных мест.
                                                    map::count прям сильно не устраивает, да? Тем более что примерно в 100% случаев вы после проверки элемента на вхождение хотите либо нему обратиться, либо его удалить, а делать лукап дважды расточительно. В общем, лучше объясняйте.
                                                    И за код на С++ получал деньги.
                                                    да, а я за код на джаваскрипте получал деньги. Предложите мне написать сайт — отправлю к профессионалам.
                                                      +2
                                                      скажем, многие из-за ABI на плюсах и пишут. Точнее, не уходят с плюсов благодаря возможности поддерживать старые кодобазы

                                                      А как насчёт новых кодобаз при этом?

                                                        0
                                                        Во во.
                                                        Поддержка старых это хорошо и полезно. Но что зачем начинать новый проект на плюсах? Вспомним Перл.
                                                          0
                                                          Но что зачем начинать новый проект на плюсах?
                                                          простой пример: вот стартуете вы абстрактный сервис. Посчитали, прикинули, получилось что при реализации на плюсах вам потребуется 1000 облачных контейнеров по 8 ядер и 30 гб памяти. А при реализации на какой-нибудь джаве — 1500 контейнеров по 16 ядер и 100 гб памяти. Смотрите вакансии и видите, что джависты еще и больше денег за работу возьмут.
                                                            0

                                                            Если я стартую абстрактный сервис для зарабатывания прибыли, то я скорее буду думать о том, как бы его быстрее на рынок вывести, и буду писать его хоть на пхп (ну там как вконтакте и фейсбук) соответственно моим навыкам и возможностям.

                                                              0
                                                              Хорошо, вы стартанули свой сервис на пхп, раскрутились, у вас куча клиентов, вы посчитали и получилось что операционные расходы слишком уж высокие, и что их можно уменьшить раза в три переписав на джаву и раз в 10 переписав на плюсы.
                                                                +3

                                                                Или наоборот, потому что на плюсах переписывать дольше, и надёжность ниже (а те, кто могут гарантировать сходный уровень надёжности, стоят больше, но всё равно пишут дольше).

                                                                  0
                                                                  под «операционными расходами» я имел в виду исключительно железо. Вот если вы всё посчитали и нашли оптимальным язык X, то флаг вам в руки, разрабатывайте на нём. Но при этом X может быть и плюсами.
                                                                    +1
                                                                    Ну то есть скорость и память. Все остальное одни минусы. Людей меньше, они дороже, писать сложнее и дольше, ошибок больше. Итд.

                                                                    Собсвенно о чем и речь. Плюсы стараниями комитета жертвуют скоростью. Также как раньше пожертвовали простотой. И в итоге ни скорости ни простоты не будет. Останется куча легаси, и никаких новых проектов.
                                                                      0
                                                                      Людей меньше, они дороже, писать сложнее и дольше, ошибок больше
                                                                      по сравнению с чем? Джаваскриптом? Ну нанимайте их, пусть они вам бекенды держащие десятки тысяч rps пишут
                                                                      Плюсы стараниями комитета жертвуют скоростью
                                                                      насколько вам будет важно быстродействие вашего приложения, если оно не будет работать?
                                                                      Также как раньше пожертвовали простотой
                                                                      приведите конкретные примеры пожалуйста
                                                                        +1
                                                                        по сравнению с чем? Джаваскриптом? Ну нанимайте их, пусть они вам бекенды держащие десятки тысяч rps пишут

                                                                        Да в общем по сравнению с любым мейнстрим языком.
                                                                        js не нравится? Ок, есть java, go, c# и иже с ними. На любом из них разработка будет быстрее и дешевле. 10к рпс любой из них выдержит, если нормально написать.

                                                                        насколько вам будет важно быстродействие вашего приложения, если оно не будет работать?

                                                                        Позволю себе процитировать недавнюю статью
                                                                        «Новые программы должны собираться из исходного кода, нам нужны инструменты, построенные на сборке из исходников, а не коллекция библиотек, которые откуда-то достали и как-то вставили в проект.

                                                                        Да, сборка из исходников — это то, чего не так просто достичь. Но нам нужно поощрять такой подход к продукту, регулярно обновлять компиляторы, чтобы люди получали пользу от новых введенных фич спустя месяц после релиза, а не через десять лет. Нужно поощрять правильные, надежные, масштабируемые и воспроизводимые решения, библиотеки с открытым исходным кодом и систему зависимостей.»

                                                                        приведите конкретные примеры пожалуйста

                                                                        Вот ranges из свеженького.
                                                                        //
                                                                        Пропустите первые два элемента диапазона и выведите только четные из следующих трех:
                                                                        for (auto const i : v
                                                                                          | rv::drop(2)
                                                                                          | rv::take(3)
                                                                                          | rv::filter(is_even))
                                                                        {
                                                                           print_elem(i);
                                                                        };
                                                                          –1
                                                                          Ок, есть java, go, c# и иже с ними. На любом из них разработка будет быстрее и дешевле
                                                                          а вот это надо доказать
                                                                          10к рпс любой из них выдержит, если нормально написать.
                                                                          а 20?
                                                                          Новые программы должны собираться из исходного кода
                                                                          а если вам приходится работать с проприетарными библиотеками? Ну вот не хотят авторы выкладывать открытый код, а с устройством работать надо. Реверс-инжинирить будете?
                                                                          Вот ranges из свеженького.
                                                                          а что, код стал сложнее? Давайте для примера:
                                                                          вот так бы мог выглядеть этот код без ренджей
                                                                          if (v.size() > 2) {
                                                                              for (size_t i = 0; i < min<size_t>(v.size() - 2, 3); ++i) {
                                                                                  if (is_even(v[i+2])) {
                                                                                      print_elem(v[i+2]);
                                                                                  }
                                                                              }
                                                                          }
                                                                          

                                                                          а ваш пример я бы записал так:
                                                                          for_each(v | rv::drop(2) | rv::take(3) | rv::filter(is_even), print);
                                                                          

                                                                          мне кажется, или стало проще?
                                                                            +1
                                                                            а вот это надо доказать

                                                                            То что на плюсах типичный сервис перекладывающий джейсоны пишется дольше чем на любом другом мейнстрим языке надо доказывать? Вы это серьезно?

                                                                            Все вот эти вот монстрики Питон + плюсы откуда по вашему появились? Писать 10500 ручек нужных каждом сервису с минимальным рпс на плюсах долго и сложно. И соответвенно дорого.

                                                                            10к рпс и 20к рпс это просто х2 серверов. На таких маштабах все должно горизонтально маштабироваться. И важнее становятся другие вопросы. Типовые и стандартные: мониторинг, логи, деплой, тестирование. С ними у плюсов я бы тоже не сказал что все хорошо.

                                                                            а если вам приходится работать с проприетарными библиотеками? Ну вот не хотят авторы выкладывать открытый код, а с устройством работать надо. Реверс-инжинирить будете?

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

                                                                            а что, код стал сложнее? Давайте для примера:

                                                                            а на нормальном языке это так пишется:
                                                                            list.stream().skip(2).limit(3).filter(this::isOdd).forEach(System.out::println);

                                                                            Земля и небо же. Правда нет любимых плюсовщиками 5 разных варинатов написания одного и того же простейшего куска. Да и форматирование кода у всех одинаковое само собой.
                                                                              +1
                                                                              Земля и небо же.

                                                                              list.stream().skip(2).limit(3).filter(this::isOdd).forEach(System.out::println);

                                                                              for_each(v | rv::drop(2) | rv::take(3) | rv::filter(is_even), print);

                                                                              Правда, что ли? Потому что в одном случае через точку, а в другом — через палочку?
                                                                                0
                                                                                10к рпс и 20к рпс это просто х2 серверов
                                                                                во-первых, не любой сервис хорошо горизонтально масштабируется, особенно если нагрузка между машинками неравномерна. Как-то наверняка отмасштабируется, но вам могут понадобиться уже не 2 а 3 сервера. А во-вторых, это удвоение операционных расходов, которое с лихвой перебьет разработку.
                                                                                Остаться на старой версии
                                                                                то есть всему миру остаться на с++17 потому что вы решили что ABI стоит постоянно ломать? А для кого тогда эти новые стандарты вообще будут?
                                                                                И приложить усилия для ухода от проприетарной заброшенной библиотеки
                                                                                почему заброшенной? Может и поддерживаемой, просто авторы останутся на старой версии, и вы вместе с ними.
                                                                                Не стоит использовать заброшенные авторами библиотеки без исходников
                                                                                вот есть у вас абстрактный измерительный прибор и библиотека для работы с ним. Ну нет другой, прибор уже влетел вам в копеечку, а пытаться измерять вручную раз в 5 дольше. Ваши действия?
                                                                                а на нормальном языке это так пишется:
                                                                                а теперь будьте добры скажите чем точка принципиально лучше вертикальной черты?
                                                                                  +1
                                                                                  во-первых, не любой сервис хорошо горизонтально масштабируется, особенно если нагрузка между машинками неравномерна. Как-то наверняка отмасштабируется, но вам могут понадобиться уже не 2 а 3 сервера. А во-вторых, это удвоение операционных расходов, которое с лихвой перебьет разработку.


                                                                                  Софт работающий с десятком к рпс должен маштабироваться горизонтально и линейно. Это прям настолько типовое требование что даже не знаю кто еще не так пишет. Там уже не 2 или 3 сервера. Там пачка контейнеров должна быть. Оркестрирование и все что полагается.

                                                                                  то есть всему миру остаться на с++17 потому что вы решили что ABI стоит постоянно ломать? А для кого тогда эти новые стандарты вообще будут?
                                                                                  Почему заброшенной? Может и поддерживаемой, просто авторы останутся на старой версии, и вы вместе с ними.

                                                                                  Все живые мигрируют. Совместимость по апи естевенно должна быть полная. Смысл не мигрировать? Для старых клиентов оставить старую версию и не трогать ее. Для всех живых мигрировать и выпустить новую. Не так сложно.

                                                                                  вот есть у вас абстрактный измерительный прибор и библиотека для работы с ним. Ну нет другой, прибор уже влетел вам в копеечку, а пытаться измерять вручную раз в 5 дольше. Ваши действия?

                                                                                  Если все совсем запущенно, то сделать прибор as service. И писать весь остальной код на чем хочется. Json спасает.

                                                                                  а теперь будьте добры скажите чем точка принципиально лучше вертикальной черты?

                                                                                  Стандартностью? Разработчики всего привыкли жать точку и IDE им показывает что можно сделать с объектом.
                                                                                    0
                                                                                    Софт работающий с десятком к рпс должен маштабироваться горизонтально и линейно
                                                                                    должен, ага. А в реальности у вас балансировка не идеальна и существуют перекосы нагрузки, которые приходится компенсировать дополнительным железом.
                                                                                    Совместимость по апи естевенно должна быть полная
                                                                                    и какая разница, совместим ли API, если вы с бинарём линкануться не можете?
                                                                                    Если все совсем запущенно, то сделать прибор as service. И писать весь остальной код на чем хочется. Json спасает.
                                                                                    посмотрел бы я как вы выхлоп промышленного векторного анализатора цепей будете в json'е гонять.
                                                                                    Стандартностью?
                                                                                    будьте так любезны, дайте ссылку на ISO
                                                                                      0
                                                                                      должен, ага. А в реальности у вас балансировка не идеальна и существуют перекосы нагрузки, которые приходится компенсировать дополнительным железом.

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

                                                                                      посмотрел бы я как вы выхлоп промышленного векторного анализатора цепей будете в json'е гонять.

                                                                                      А в чем проблема? Я понимаю там в лейтенси упереться можно, да и то маловероятно. А с объемами какие проблемы? Нынче 10g в пределах ДЦ это норма. Разделяем все по контейнерам как удобно, о сети в пределах ДЦ можно не беспокоится.

                                                                                      будьте так любезны, дайте ссылку на ISO

                                                                                      Ок, жать точку после имени объекта для получения списка возможных действий для программистов нестандартно и неестественно. Продолжайте есть кактус, я не против.
                                                                                        0
                                                                                        И? Маштабируемся линейно, запас должен быть. Нагрузка увеличилась в 2 раза, надо в 2 раза больше ресурсов
                                                                                        повторюсь: проблема может быть в неравномерности нагрузки. Я сталкивался с тем, что перенарезание на меньшее число больших подов (с той же суммой ядер/памяти) давало прирост.
                                                                                        А в чем проблема? Я понимаю там в лейтенси упереться можно, да и то маловероятно. А с объемами какие проблемы? Нынче 10g в пределах ДЦ это норма
                                                                                        вы как собрались конвертировать скажем гигабит бинарных данных в json и обратно?
                                                                                        … нестандартно и неестественно.
                                                                                        допустим я согласен что пайп менее естественнен чем точка. Но я хоть убей не понимаю почему разница кажется вам существенной
                                                                                          0
                                                                                          повторюсь: проблема может быть в неравномерности нагрузки. Я сталкивался с тем, что перенарезание на меньшее число больших подов (с той же суммой ядер/памяти) давало прирост.

                                                                                          Есть у нас что-то работающее с рпс (а не считающий процессинг), то это все будет в пределах десятков процентов. Можно не обращать внимания.

                                                                                          вы как собрались конвертировать скажем гигабит бинарных данных в json и обратно?

                                                                                          Гигабит это примерно 100 мегабайт в секунду. Желательно быстрее секунды, мы тем же потоком хотим еще что-то делать.
                                                                                          Не будем гадать, а лучше напишем наивный тест. Никаких оптимизаций, никакой паралельности. Ничего. Прямо и в лоб. Сериализатор вот этот https://github.com/alibaba/fastjson
                                                                                              static class Data {
                                                                                                  public byte[] val;
                                                                                              }
                                                                                          
                                                                                              public static void main(String[] args) {
                                                                                                  Random random = new Random();
                                                                                          
                                                                                                  List<Data> dataList = new ArrayList<>(); //100Mb will be here
                                                                                                  for(int i=0; i<1000; ++i) {
                                                                                                      Data data = new Data();
                                                                                                      data.val = new byte[1024 * 100]; //100k bytes
                                                                                                      random.nextBytes(data.val);
                                                                                                      dataList.add(data);
                                                                                                  }
                                                                                          
                                                                                                  long time = System.currentTimeMillis();
                                                                                                  for(int i=0; i<100; ++i) { //10G total
                                                                                                      dataList.stream().forEach(JSON::toJSONString);
                                                                                                  }
                                                                                                  long time2 = System.currentTimeMillis();
                                                                                                  System.out.println(time2-time);
                                                                                              }
                                                                                          

                                                                                          На jdk11 и моем стареньком i5 получилось 19767 миллисекунд. Или 19 секунд на 10 гигабайт. Или 0.2 секунды на 100 мегабайт. Пусть даже мои измерения неточные и ошибаются в пару раз времени у нас остается с запасом. И это всего лишь одно старенькое ядро. Вопросы?
                                                                                            0
                                                                                            примерно всё что вы сделали — вставили "\", \"" на каждые 100кб, это считай as is, но УЖЕ занимает у вас 20% ресурса проца. А теперь представьте что у вас гигабит float'ов
                                                                                              0

                                                                                              Вы выразили недоумение как я собрался сериализовать гигабит двоичных данных. Я написал тест и показал что это всего лишь 0.2 цпу.


                                                                                              Мне написать тест перекладывающий флоат в 4 байтика? Или на слово поверите что там проблем с производительностью не будет?

                                                                                                0
                                                                                                Мне написать тест перекладывающий флоат в 4 байтика?
                                                                                                вы кажется забыли что json — текстовый протокол, а представление флоата в тексте — не «4 байтика».
                                                                                                  –1

                                                                                                  Сериализацию массива байтиков в json я уже написал. Скорость померял. Осталось написать конвертацию флоатов в массив байтиков и задача сводится к решенной.

                                                                                          0
                                                                                          Ок, жать точку после имени объекта для получения списка возможных действий для программистов нестандартно и неестественно.

                                                                                          Это естественно, но нерасширяемо. Идея-то была в том, что допустимые действия может "добавить" любая библиотека, а не только стандартная. С точкой так уже не получится.

                                                                                  0
                                                                                  10к рпс любой из них выдержит, если нормально написать.
                                                                                  а 20?
                                                                                  10k, 20k… когда Pokemon Go запустили Google получил 700k «лишних», «нерасчётных» Qps. Ещё раз — это не то, что он обрабатывал, это сколько запросов было получено сверх того, что Niantic заказал и оплатил в предварительной заявке.

                                                                                  Как результат — было принято решение всегда иметь «в запасе» мощности под лишние 1M qps…
                                                                                  +1

                                                                                  Да вроде не такие рэнжи и страшные, по крайней мере этот пример. Через точку было бы проще конечно, но это долгая история, уже обсуждали на хабре.

                                                                                    +1
                                                                                    Через operator | тоже норм любому, кто имел дело с шеллом, вполне интуитивно понятно.
                                                                                      0
                                                                                      кто имел дело с шеллом

                                                                                      хипстеры сэр //cарказм

                                                                                      0
                                                                                      Это первое что попалось под руку. Страшных и типичных примеров кода на плюсах море везде.
                                                                                        +1

                                                                                        Ну так их фиксят потихоньку. Тут проблема не в страшности эстетической, а в том что от ощущения ходьбы по минному полю не отделаться. Т.е. даже те кто пишет код на плюсах 24на7 бывает не знает всех тонкостей и правил типа когда какая перегрузка срабатывает и подобных. А я и подавно.

                                                                  0
                                                                  map::count прям сильно не устраивает, да?

                                                                  Да сильно. Ибо нелогично, а им и так сложно. Проверка наличия это типовой сценарий для хешмапы. Хешмапы, O(1), вот это вот все. Проверяй, получай, удаляй. Дешево. Пиши смело, софт будет работать хорошо. Студенты, закапываться в тонкости реализации нельзя.
                                                                    0
                                                                    Студенты, закапываться в тонкости реализации нельзя.
                                                                    Как у вас студенты сдают структуры данных и потом не понимают почему делать двойной лукап это плохо?
                                                                      0
                                                                      Даже если это в чистом виде двойной, а не что-нибудь вроде
                                                                      «если нет запускаем вот этот рассчет и кладем результат в мапу», то все равно экономия на спичках. Читаемость, простота и понятность важнее.
                                                                        0

                                                                        Если на каждое такое простое действие будет делать в два раза больше движений, то и вся программа будет работать в два раза дольше. А contains() можно было добавить, это сахар, кстати в C++20 добавили.

                                                                          0
                                                                          Два это контанта. Пофиг. Не из-за этого софт тормозит.

                                                                          Синтаксический сахар это наше все. Все языки его вводят в оптовых количествах. Проще разработка, понятнее исходники, приятнее писать, меньше ошибок. Вот это вот все.

                                                                          Ввели и хорошо. Всего-то лет 20 прошло от того момента когда надо было вводить. Пойду поищу следующую такую же очевидную вещь которую надо было лет 20 назад ввести в стандарт.
                                                                            +3
                                                                            Два это контанта. Пофиг. Не из-за этого софт тормозит.
                                                                            Два это «не совсем константа» и тормзит именно из-за неё.

                                                                            В развитой инжереной дисциплине улучшение в 12%, легко получаемое, никогда не рассматривается как несущественное — и я верю, что подобный же подход должен возобладать и в програмимровании.
                                                                            Это, собственно, цитата из той самой статьи откуда вырвали из контекста (и подняли на флаг, чтобы оправдать создание груды дерьма) цитату про «преждевременную оптимизацию».

                                                                            Ну потому что Петя сделает два вызова вместо одного (два же — это константа, пофиг), Вася сделает на своём уровне то же самое, Таня и Коля… а когда у вас этих слоёв с десяток — получаем эффективность всей конструкции в 0.1%.

                                                                            P.S. И да, конечно изначальное зло — это, собственно, наличие этого десятка уровней абстракции… но зачастую с этим ничего поделать нельзя: ну не умещается программа на миллион строк в голове у одного человека… ну никак.
                                                                              –1
                                                                              На практике находится микросервис в который миллион запросов уходит по одному. По очереди. И после простейшей переделки на балк все начинает работать быстро. А все эти коэфициенты 2 для О(1) ничего не меняют.

                                                                              Два для О(1) это всего лишь два. Чтобы получить 0.1% надо повторить много раз. Я с трудом представляю себе такую конструкцию. И скорее всего в ней будут гораздо более серьезные проблемы.
                                                                                0
                                                                                Я с трудом представляю себе такую конструкцию.
                                                                                Посмотрите на свой телефон. Или на свой веб-сайт. Запрос пары байт из базы проходит обычно от 20 до 30 «слоёв абстракции». И нет, там нет замедления в тысячу или в миллион раз… именно потому что авторы этого всего знают о том, что два — это не много, а очень много. 12%, указанные Кнутом — нормально.

                                                                                По очереди. И после простейшей переделки на балк все начинает работать быстро.
                                                                                Если всё так чудесно, то почему больше нет веб-сайтов, которые бы не тормозили? Почему открытие документика на мегабайт в Google Docs на современном железе занимает столько же, сколько открытие такого же документа на эталонной IBM PC XT на 4.7Mhz в MIM (и да, я не издеваюсь: MIM вполне открывал такие файлы на IBM PC XT с 256Kb RAM)?

                                                                                Да, я понимаю, новые возможности, коллаборация, всё такое… но машинка у нас даже не тысячу раз быстрее, а в десять тысяч раз быстрее сегодня!
                                                                                  0
                                                                                  Мой теперешний телефон. Неновый и недорогой работает лучше и быстрее мой прошлый телефон. Не вижу проблем. Мой сайт я точно знаю обо что и где тормозит. И слои абстракции в его тормозах точно не виноваты. И даже если сверху накрутить еще десяток слоев на Питоне по сути ничего не изменится.

                                                                                  Если всё так чудесно, то почему больше нет веб-сайтов, которые бы не тормозили? Почему открытие документика на мегабайт в Google Docs на современном железе занимает столько же, сколько открытие такого же документа на эталонной IBM PC XT на 4.7Mhz в MIM (и да, я не издеваюсь: MIM вполне открывал такие файлы на IBM PC XT с 256Kb RAM)?

                                                                                  Вы серьезно? На XT у вас не было возможностей сделать за пару нажатий кнопок документы с современным оформлением и форматированием. За эти возможности надо платить.
                                                                                  Быстродействия должно быть достаточно. Быстрее часто просто не надо. Средний пользователь на среднем компе доволен и хорошо. Зачем тратиться на дальнейшее ускорение? Лучше фичу запилить.

                                                                                  Если хочется тех интерфейсов и даже расширенных (по сравнению с теми временами) возможностей есть vim. Работает моментально на всем. Функционала гораздо больше чем тогда было. И он даже удобнее чем редакторы тех времен.

                                                                                  Выбор есть. Пользуйтесь чем хочется. Никто не принуждает же.
                                                                                    0
                                                                                    За эти возможности надо платить.
                                                                                    Почему я должен платить за возможности, которые мне нафиг не нужны?

                                                                                    На XT у вас не было возможностей сделать за пару нажатий кнопок документы с современным оформлением.
                                                                                    Была, конечно. Достаточно было использовать нужный \documentclass. И при этом при переносе из издания в издание формат менялся автоматом.

                                                                                    Выбор есть. Пользуйтесь чем хочется. Никто не принуждает же.
                                                                                    Как мне с помошью VIM'а прочитать ваш и оставить свой оставить комментарий на Хабре?

                                                                                    Собственно всё, что нужно знать о современной разработке — это тот факт, что четверть века назад в журналах было полно статетей про то, что и как нужно сделать в системе, чтобы поставить новую версию Turbo Pascal или Windows… а сегодня — не меньшее число статей о том, как избежать обновлений. И огромное количество людей воспринимают информацию о том, что кто-то где-то выпустил обновление не как повод порадоваться новым возможностям, а как зло, с которым всё тяжелее и тяжелее бороться.

                                                                                    Отчасти это, конечно, обусловлено тем, что раньше те, кто обновляться не хотел могли ничего не делать, а теперь, наоборот им и приходится прилагать дикие усилия… но, с другой стороны, тот же Debian появился в 1993м году, автообновления там появяились примерно тогда же и, насколько я знаю, никогда такого потока статей в духе «как остановить этот беспредел, творимый Windows 10» он не вызывал…
                                                                                      0
                                                                                      Почему я должен платить за возможности, которые мне нафиг не нужны?

                                                                                      Потому что они сделаны для среднего пользователя. Он согласен. Мейнстрим всегда идет за массой. Для всех остальных есть разные варианты.

                                                                                      Как мне с помошью VIM'а прочитать ваш и оставить свой оставить комментарий на Хабре?

                                                                                      Какой Хабр. Во времена XT даже модемы были экзотикой. А тут и картинки, и автоподгрузка, и редактор. Не хотите не пользуйтесь. Ресурсы похожие на ресурсы тех времен (хотя опять таки гораздо лучше) и не требующие никакой производительности от клиентов живы. Кто хочет берет и пользуется ими. Выбор есть.

                                                                                      Судя по всем статистикам народ обновляется. Массово и без особых проблем. Отклонения есть, но достаточно незначительные чтобы ими пренебречь.
                                                                                      Win10 80% store.steampowered.com/hwsurvey/Steam-Hardware-Software-Survey-Welcome-to-Steam?platform=combined
                                                                                      Win10 40% radar.yandex.ru/desktop?selected_rows=XtlYgg%252Cn2QA91
                                                                                      Доля везде растет. Все ок.

                                                                                      К чему приводят необновления все в it уже в курсе. Скоро каждая лампочка обновлятьcя начнет. И мир от этого станет только лучше.
                                                                                      www.forbes.com/sites/thomasbrewster/2016/09/25/brian-krebs-overwatch-ovh-smashed-by-largest-ddos-attacks-ever/#74c3f5855899
                                                                                        +2
                                                                                        Во времена XT даже модемы были экзотикой.
                                                                                        Не были. CBBS появилась в 1978м году, а XT, как бы, через 5 лет. Compuserve же поддерживал чаты и форумы с 70х — тоже всё до появления XT.

                                                                                        Не хотите не пользуйтесь.
                                                                                        Это, кстати, неплохая идея — нужно будет обдумать.

                                                                                        Ресурсы похожие на ресурсы тех времен (хотя опять таки гораздо лучше) и не требующие никакой производительности от клиентов живы.
                                                                                        О! Ну вот давайте обсудим «ресурс тех времён» — GO BPROGA (описанный, в частности, в README к Turbo Pascal 4.0 прямо в дистрибутиве, а появившийся ещё раньше). С форумами, где можно связаться с разработчиками прочим.

                                                                                        Что посоветуете? Ну, такого, чтобы «не требующие никакой производительности от клиентов»?

                                                                                        Судя по всем статистикам народ обновляется. Массово и без особых проблем.
                                                                                        Масово обновляется — это когда через год после выхода Windos 95 уже больше половины пользователей работают с ней, а через две Windows 3.x уже не поддерживается почти никакими новыми программами.

                                                                                        А когда система, вышедшая более 10 лет назад, и более вообще официально не поддерживаемая, оказывается более популярна, чем вышедшая 4 года назда замена… то это не «массово обновляется», это «несмотря на все прилагаемые усилия производителям удаётся заставить пользователей обновиться… иногда… если повезёт».

                                                                                        К чему приводят необновления все в it уже в курсе.
                                                                                        К тому, что моя мать может не тратить денег на новое железо и спокойно смотреть ролики на YouTube с помощью компьтера на Intel Atom десятилетней давности?

                                                                                        Скоро каждая лампочка обновлятьcя начнет.
                                                                                        Это вряд ли. Для этого нужно будет, чтобы кто-то выпуска обновления для этих лампочек. А зачем это нужно если можно, вместо этого, продать вам новую?

                                                                                        И мир от этого станет только лучше.
                                                                                        www.forbes.com/sites/thomasbrewster/2016/09/25/brian-krebs-overwatch-ovh-smashed-by-largest-ddos-attacks-ever/#74c3f5855899
                                                                                        Это вы называете «мир стал лучше»? Что помешало сделать эти долбаные камеры не подверженными уязвимостям изначально? Новомодный принцип «хуя… и в продакшн» («хуя… — это потому что традиционный „хуяк-хуяк“ это нынче слишком дорого и сложно)?

                                                                                        То, что нынче каждая лампочка норовит обновиться по поводу и без повода — сделало мир только хуже, на самом деле. И не потому, что сами по себе обновления — зло. А потому что это позволило разработчикам перестать думать о надёжности и безопасности. Лепи любое гавно, потом выпустим обнову, всё исправим!
                                                                                          0
                                                                                          О! Ну вот давайте обсудим «ресурс тех времён» — GO BPROGA (описанный, в частности, в README к Turbo Pascal 4.0 прямо в дистрибутиве, а появившийся ещё раньше). С форумами, где можно связаться с разработчиками прочим.

                                                                                          Что посоветуете? Ну, такого, чтобы «не требующие никакой производительности от клиентов»?

                                                                                          Предложу начать с мейл листов. Ну хотя бы вот отсюда https://lkml.org/ Клиента не требующего ресурсов сами найдете?

                                                                                          А когда система, вышедшая более 10 лет назад, и более вообще официально не поддерживаемая, оказывается более популярна, чем вышедшая 4 года назда замена… то это не «массово обновляется», это «несмотря на все прилагаемые усилия производителям удаётся заставить пользователей обновиться… иногда… если повезёт».

                                                                                          Софт стал настолько хорош что можно бежать чуть медленее. Геймеры бегут быстрее, все остальные медленее. Но бегут все. Ну и заодно стоит поблагодарить всех за совместимость. Много-много лет совместимости. Во времена win3.1 такой совместимости не было.

                                                                                          К тому, что моя мать может не тратить денег на новое железо и спокойно смотреть ролики на YouTube с помощью компьтера на Intel Atom десятилетней давности?

                                                                                          Это же ужастно. Могли бы и подарить чего посвежее. Атомы тормозили с момента выхода.

                                                                                          Это вряд ли. Для этого нужно будет, чтобы кто-то выпуска обновления для этих лампочек. А зачем это нужно если можно, вместо этого, продать вам новую?

                                                                                          Совместимость и стандарты. Всех заставят. Как продать новую маркетологи придумают, я за них вообще не переживаю.

                                                                                          А потому что это позволило разработчикам перестать думать о надёжности и безопасности. Лепи любое гавно, потом выпустим обнову, всё исправим!

                                                                                          Предлагаю начать с написания кода без багов. Вот заживем.
                                                                                            +1
                                                                                            Предложу начать с мейл листов. Ну хотя бы вот отсюда lkml.org Клиента не требующего ресурсов сами найдете?
                                                                                            LKML — это хороший пример старого проекта, сохранившего верность старым традициям. К сожалению это — скорее редкое исключение, чем правило. Новых проектов, появившихся в последние лет 10 и использующих списки рассылки для общения вместо веб-сайтов типа того же GitHub'а, я пожалуй, не назову ни одного.

                                                                                            Во времена win3.1 такой совместимости не было.
                                                                                            Была, конечно. Почти все программы под DOS отлично работали на любой версии от 3.30 и новее. И программы для Windows 3.1 работают аж даже в Windows 10 (32-битной, правда).

                                                                                            Просто быстрый переход на Windows 95 позволил так же быстро отказаться от поддержки Windows 3.1. Несмотря даже на то, что ради этого перехода многим приходилось докупать память и иногда компьютеры целиком.

                                                                                            Это же ужастно. Могли бы и подарить чего посвежее. Атомы тормозили с момента выхода.
                                                                                            Пробовал — не получается. Старые люди «прикипают» к вещам. Вот нравится ей вот конкретно этот моноблок (который моей сестре выдали на обанкротившейся фирме вместо зарплаты) — и хоть ты тресни. Собственно основная претензия — как у всех: у Windows 10 ну вот севершенно «неправильное» стартовое меню… и вообще все кнопочки. Когда YouTube перестанет поддерживать и Firefox 52… придётся что-то придумывать.

                                                                                            Всех заставят.
                                                                                            Это кто и как их заставит? Пока что даже подавляющее большинство моделей смартфонов ни одной обновы за всю свою жизнь не получает, не говоря уже про роутеры, а вы хотите, чтобы лампочки кто-то вам обновлял…

                                                                                            Предлагаю начать с написания кода без багов. Вот заживем.
                                                                                            Ну совсем без багов — это вряд ли. А без возможности удалённо взломать систему — можно железку сделать… только мало кому нужно.
                                                                                              0
                                                                                              LKML — это хороший пример старого проекта, сохранившего верность старым традициям. К сожалению это — скорее редкое исключение, чем правило. Новых проектов, появившихся в последние лет 10 и использующих списки рассылки для общения вместо веб-сайтов типа того же GitHub'а, я пожалуй, не назову ни одного.

                                                                                              Значит они не востребованны. Востребованные проекты делают и живут без проблем. Могу предложить пользоваться теми ресурсами которые нравятся ине пользоваться теми которые не нравятся. Выбор, пусть даже в некоторых случаях и не особо богатый, есть. В конце концов вы же программист. Контрибутить в проекты по своему вкусу это хорошо.

                                                                                              Просто быстрый переход на Windows 95 позволил так же быстро отказаться от поддержки Windows 3.1. Несмотря даже на то, что ради этого перехода многим приходилось докупать память и иногда компьютеры целиком.

                                                                                              Не. Вышло все не поддерживающее win3.1. Вот примерно вообще все. И у людей не было выбора. Пришлось обновляться. А сейчас все поддерживают старые версии очень долго.

                                                                                              Это кто и как их заставит? Пока что даже подавляющее большинство моделей смартфонов ни одной обновы за всю свою жизнь не получает, не говоря уже про роутеры, а вы хотите, чтобы лампочки кто-то вам обновлял…

                                                                                              Где вы такие телефоны берете? Даже более-менее приличные китайы обновляются минимум пару лет с даты выхода. Самсунги с Эплами получают обновления заметно долше.

                                                                                              Ну совсем без багов — это вряд ли. А без возможности удалённо взломать систему — можно железку сделать… только мало кому нужно.

                                                                                              Без багов и без возможности удаленного взлома это синонимы. Сейчас почти все смотрит в интернет. С приходом ipv6 вообще все будет смотреть в интернет. А баги в типовых библотеках и операционках находят регулярно.
                                                                                                0
                                                                                                Где вы такие телефоны берете?
                                                                                                Я их нигде не беру. Но это не значит, что их нет.

                                                                                                Даже более-менее приличные китайы обновляются минимум пару лет с даты выхода.
                                                                                                Что, собственно, и отличает их от «неприличных». Коих по количеству моделей (но не факт, что по продажам) — большинство.

                                                                                                Без багов и без возможности удаленного взлома это синонимы.
                                                                                                Нет, не синонимы ни разу. Чтобы не было возможности удалённого взлома нужно не так много вещей: драйвер сетевой карты без уязвимости, да проверка сертификата без таких же проблем. И то и другое можно, при желании, сделать. Да, не совсем тривиально и обойдётся не совсем крошечные деньги — но это возможно.

                                                                                                А баги в типовых библотеках и операционках находят регулярно.
                                                                                                Их там находят ровно потому что никому не нужно и неинтересно тратить время и силы на написание софта без багов.

                                                                                                Вот посмотрите сюда… ну или сюда. Вы хотите сказать, что MTA — более простая задача, чем прошивка, опрашивающая три датчика и рисующая три формочки (а это типичной объём функциональности в IoT лампочке)? Не смешите мои тапочки, пожалуйста.

                                                                                                Вся эта бесконечная истерия по поводу «борьбы за безопасность», одновления и прочее — это театр. Он призван обеспечить у людей ощущение того, что за их безопасность «усиленно борются». Если бы кому-то безопасность была реально интересна — её можно было бы обеспечить… но это — никому не нужно.
                                                                                                  +1
                                                                                                  Вот посмотрите сюда… ну или сюда. Вы хотите сказать, что MTA — более простая задача, чем прошивка, опрашивающая три датчика и рисующая три формочки (а это типичной объём функциональности в IoT лампочке)? Не смешите мои тапочки, пожалуйста.

                                                                                                  Лампочке надо слушать порт. Все же хотят ее с телефона включать. Значит ОС, http, json, пароли, сертификаты. И полный набор всего типового софта следом. Не писать же ради лампочки вот это вот все.

                                                                                                  Вся эта бесконечная истерия по поводу «борьбы за безопасность», одновления и прочее — это театр. Он призван обеспечить у людей ощущение того, что за их безопасность «усиленно борются». Если бы кому-то безопасность была реально интересна — её можно было бы обеспечить… но это — никому не нужно.

                                                                                                  Там где обновляют софт там проблем гораздо меньше.
                                                                                                  Вспомним недавние эпидемии шифровальщиков. Обычное обновление полностью от них защищало.

                                                                                                  Безопасность и обеспечили, утечки и взломы из-за 0day уязвимостей происходят гораздо реже чем из-за необновляемого софта или кривых рук настройщиков.
                                                                                                  По сути нерешаемые дыры только во всяких iot остались. Компы, телефоны, да даже роутеры обновляются и проблем в среднем не имеют.
                                                                                                    0

                                                                                                    Дыр в китайских прошивок достаточно. И во многом потому что там какой то пхп веб морда на коленке с sql инекциями. Потому что фреймворки, которые позволяют не думать, не влазят в память роутера.

                                                                                                      0
                                                                                                      Вспомним недавние эпидемии шифровальщиков.
                                                                                                      Вспомним, да. И вспомним о том, что компьютер моей матери (XP, напоминаю) их не заметил. А обновления на него не приходили… давно, однако.

                                                                                                      Обычное обновление полностью от них защищало.
                                                                                                      Если «обычное обновление» от них защищало — то откуда тогда взялись эпидемии?

                                                                                                      Безопасность и обеспечили, утечки и взломы из-за 0day уязвимостей происходят гораздо реже чем из-за необновляемого софта или кривых рук настройщиков.
                                                                                                      Результат такой же, как если бы вы пришли куда-нибудь, сели посреди комнаты, оставили дурно пахнущую кучу — и повесили бы вентилятор, чтобы пахло чуть поменьше.

                                                                                                      Компы, телефоны, да даже роутеры обновляются и проблем в среднем не имеют.
                                                                                                      Не знаю где вы обнаружили обновляемые роутеры. Не могу сказать, чтобы я роутеров видел уж сильно много, но ни одного, к которому выходили бы обновления прошивки больше одного-двух лет я не видел. А эксполуатируются они по 5-10 лет легко.

                                                                                                      По сути нерешаемые дыры только во всяких iot остались.
                                                                                                      Ну если рассуждать как авторы статей This aggressive IoT malware is forcing Wi-Fi routers to join its botnet army (свежая статья, кстати, конец прошлого года) — то да, наверное. А если в IoT записать и датацентры Гугла и смартфоны с синхрофазотронами — то вообще ничего, кроме IoT уязвимостей не имеет…
                                                                                                        0
                                                                                                        Вспомним, да. И вспомним о том, что компьютер моей матери (XP, напоминаю) их не заметил. А обновления на него не приходили… давно, однако.

                                                                                                        Я очень хочу верить что люди со статьями на Хабре способны настросить комьютеры и роутеры в своей эпсион окресности так чтобы их вирусы не касались. А вот всякие рабочие сети заражаются. Там всем пофиг. Особенно в гос и около гос конторах. Им тлько обновления помогут.

                                                                                                        Не знаю где вы обнаружили обновляемые роутеры. Не могу сказать, чтобы я роутеров видел уж сильно много, но ни одного, к которому выходили бы обновления прошивки больше одного-двух лет я не видел. А эксполуатируются они по 5-10 лет легко.

                                                                                                        Все не совсем ужастный китай вполне себе обновляются. Иногда надо приложить руки, но обновляются. Хочется верить что следующее поколение даже без прикладывания рук обновляться сможет.

                                                                                                        Ну если рассуждать как авторы статей This aggressive IoT malware is forcing Wi-Fi routers to join its botnet army (свежая статья, кстати, конец прошлого года) — то да, наверное. А если в IoT записать и датацентры Гугла и смартфоны с синхрофазотронами — то вообще ничего, кроме IoT уязвимостей не имеет…

                                                                                                        Да в общем тоже самое. В ДЦ Гугла нет проблем. Их БД никто не продает, значит инкто не сломал. Не ставишь обновления — у тебя проблемы. Нет обновлений — у тебя проблемы. Не надо покупать устройства которые не поддерживаются и не обновляются. Маркетологи скоро это поймут и начнут рекламировать соответвенно.
                                                                                                          0
                                                                                                          А вот всякие рабочие сети заражаются. Там всем пофиг. Особенно в гос и около гос конторах. Им тлько обновления помогут.
                                                                                                          Не помогут. Если бы помогало — никаких эпидемий WannaCry не было бы.

                                                                                                          Их БД никто не продает, значит инкто не сломал.
                                                                                                          Странная логика. Не знаю — имеют ли спецслужбы их БД сейчас, но как история со Сноуденом показала — несколько лет назад у спецслужб базы были. А может и не только у спецслужб. А в переходах в метро — не продавались и на ThePirateBay не лежали.

                                                                                                          Маркетологи скоро это поймут и начнут рекламировать соответвенно.
                                                                                                          Судя по тому, сколько усилий прилагается к противоположному (это и Project Treble и все эти все эти APEXы) — всё движется скорее в обратном направлении.
                                                                                                            +1
                                                                                                            Не помогут. Если бы помогало — никаких эпидемий WannaCry не было бы.

                                                                                                            Ровно от него обновления и помогали. По этой эпидемии очень хорошо стало понятно кто не обновляется.

                                                                                                            Странная логика. Не знаю — имеют ли спецслужбы их БД сейчас, но как история со Сноуденом показала — несколько лет назад у спецслужб базы были. А может и не только у спецслужб. А в переходах в метро — не продавались и на ThePirateBay не лежали.

                                                                                                            Логика простая. Кто что кому отдает добровольно в данном случае не очень интересно. А вот украть не могут. Иначе бы продавали. История со Сбером очень показательна. 2 доллара за полную историю транзакций любой карты.
                                                                                                              0
                                                                                                              Логика простая
                                                                                                              И неверная.

                                                                                                              Кто что кому отдает добровольно в данном случае не очень интересно
                                                                                                              Вот только Google никому ничего «добровольно» не отдавал. Вы бы почитали то, что Сноуден накопал перед тем, как в теории заговора удаляться.

                                                                                                              Спецслужбы даже не стали взламывать ничего. А воспользовались тем, что в былые времена у Гугла не было шифрования данных внутри локальной сети и в эту сеть входили роутеры, арендуемые у магистральных провайдеров, больших и малых.

                                                                                                              Спецслужбы тупо сломали один такой и получили возможность видеть всё, что происходит в сети.

                                                                                                              Ошибка в дизайне и ваш любимый IoT, никакого заговора.
                                                                                                                0
                                                                                                                Сноуден столько чуши понаговорил уже. Он вообще не авторитет.

                                                                                                                Шифровать внутрисетевой трафик надо. Никто с этим не спорит. Этим по сути недавно озаботились. Роутеры и прочее тут не причем. Ошибка дизайна большой системы. Бывает. Поправят.

                                                                                                                В мега утечку из Гугла я все равно не верю. Такое всегда выплывает и продается. Спецслужбы первые идут продавать то что у них есть. Все базы всех госорганов продаются. Массово и недорого.
                                                        +2

                                                        Это только пока вы не имеете дело ни с чем сложнее char'ов и int'ов.

                                                        –1
                                                        почитайте, рекомендую
                                                          0
                                                          Суть серии статей, в общем-то, как всегда не техническая.

                                                          Суть примерно такая — функциональщики мало внимания уделяют реальному миру и много виртуальным алгоритмам. Сишники много возятся с реальностью (процессоры, регистры, железные оптимизации) и мало с виртуальностью (математика вообще). В итоге два мира смотрят друг на друга свысока, но всё же сишники несколько завидуют функциональщикам, ведь те реально демонстрируют знание каких-то разделов математики, хоть и мало полезных, но не изученных оппонентами. И вот эта неизученность гложет. А тут повод — можно заткнуть за пояс «этих математиков». Отсюда серия статей.

                                                          На самом деле обе стороны ничуть не лучше в плане интеллекта, но просто у них разная специализация. А математическая «продвинутость» (как кажется функциональщикам) есть лишь следствие необходимости изучать подаваемый именно с математической точки зрения материал о своих любимых ЯП. При этом абстрактные высоты, естественно, затмевают низкий уровень, начинает казаться, что там внизу одни негры делают грязную работу. Ну и далее очень быстро возникает желание поучать негров, например бенчмарками ФП vs С. Только в данном случае, так сказать, нашла коса на камень.

                                                          И урок из данной темы, на мой взгляд, стоит в первую очередь извлекать именно функциональщикам. Чисто психологический — не зазнавайтесь. А вот сишникам (и прочим сторонникам низкоуровневых подходов) всё же стоит интересоваться альтернативными подходами к программированию, просто что бы не на случайном удачном примере о производительности рассуждать, а (по возможности) на равных отметать высокомерные заявления некоторых функциональщиков именно на их территории. Но для этого нужно изучать чужие подходы. И как раз такое занятие не нравится ни функциональщикам, ни сишникам.

                                                          Нужно учиться понимать друг друга. Банально, но пока оба мира не интересуются друг другом, будет только вот такая «мягкая» война, когда неудачный пример одной стороны вызовет бурю ликования с другой (ну ладно, не ликования, а разумеется, взвешенного анализа, но с целью показать, что оппоненты слабаки и не увидели того, что на самом деле нужно было увидеть).

                                                          Разрыв между двумя лагерями вроде бы очевиден, но оба лагеря не хотят этот разрыв ликвидировать. И потому война (в мягком виде) продолжается. Поэтому стоит подумать именно о психологических причинах происходящего. Ну и написать статью «Почему С лучше Хаскеля», но за авторством функционального сообщества, а потом «почему Хаскель лучше С», но за авторством сообщества низкоуровневой разработки. То есть честно признать плюсы оппонентов. Как бы психологически трудно это не было.
                                                            +5

                                                            Ваша лирика это всё правильно, но как же статья не техническая? что ни одна из тех что были на хабре? Какой тех части вам не хватает? Проблема в том что в хаскель коде от фп остались только циклы через рекурсию. Конечно всё еще есть гарантии по поводу сайд эффектов, но в рамках одного куска кода это значения не имеет.

                                                              0
                                                              Проблема в том что в хаскель коде от фп остались только циклы через рекурсию.

                                                              Вы так говорите, как будто они там были до оптимизации.


                                                              Какие куски ФП для этой задачи вообще ещё можно было бы применить? Только не из любви к искусству и не ради выпендривания моноидами (как в совсем исходной статье, на которую я отвечал), а чтобы было понятнее, читабельнее, идиоматичнее и так далее.


                                                              Конечно всё еще есть гарантии по поводу сайд эффектов, но в рамках одного куска кода это значения не имеет.

                                                              Зато это гарантирует, что я могу эту функцию вызывать на двух разных файлах параллельно и не иметь проблем. Значимая часть из предложенных реализаций на С таким свойством не обладают (потому что пишут статистику в глобальную переменную, например).

                                                                0

                                                                Я имел ввиду набор из map/filter/reduce и прочих штучек, которые теоретически можно было ожидать в подобной задаче. Мне комментатор выше предлагал познать высокие материи фп (ничего против них не имею), но они для моего сравнения не нужны. Они покажут себя только на более большой кодовой базе. Больше никакого подтекста.

                                                                  0

                                                                  Так BS.fold и есть этот самый reduce.


                                                                  Ну и все упомянутые вами комбинаторы выражаются через рекурсию (что неудивительно) и могут быть записаны с явной хвостовой рекурсией, что может компилироваться в простой цикл (правда, у конкретно свёрток тут есть тонкости, но на этом уровне рассмотрения это неважно).

                                                            0
                                                            В данной заметке мы рассмотрели способы оптимальной реализации алгоритма Вагнера-Фишера, который требует O(n*m) времени (два вложенных for). Хотя по ссылке выше есть и алгоритм Хиршберга, который работает за линейное время

                                                            Статья отличная, но вот в данном предложении, вроде бы, должна быть память, а не время, время и там, и там — квадрат.
                                                              0

                                                              И правда, вот это я не внимательно прочитал. Память у нас уже линейная т.к. если нужно знать только расстояние то всю матрицу сохранять не надо. Так что Хиршберг тут ничего не даст.

                                                                0
                                                                Да, вы правы, но Хиршберг позволяет восстанавливать ответ, то есть указывать, какие символы надо заменить, удалить, вставить, чтобы получить другую строку, и делает это за линейную память. Стандартный алгоритм требует всю матрицу для востановления, то есть квадратичную память. :)
                                                              0
                                                              Сравнивается в таких случаях естественно с неоспоримым лидером в производительности — С/C++
                                                              Сильное заявление. Проверять его я, конечно же, не буду.
                                                              Лидерство С/C++ давно оспорено ЯП, не обладающими бременем совместимости ABI
                                                              habr.com/ru/company/yandex/blog/488588
                                                              habr.com/ru/post/480608
                                                                0

                                                                ABI это про стандартную библиотеку, тоже важно, но не так критично.
                                                                А про бенчмаркинг-гейм можно писать отдельно похожие разборы, хотя С там все ещё первый.
                                                                Если с ним сравнивают, и очень радуются когда удается его догнать, то утверждение косвенно подтверждается. Проверить утверждение полностью я действительно не могу.

                                                                  0

                                                                  К осмысленности результатов benchmark game у меня (да и не только) есть, скажем так, философские вопросы. По факту там бенчмаркается скорее не реализация языка, а поддержка компилятором интринсиков, инлайн-ассемблера и тому подобных вещей. Смысл такого от меня ускользает, особенно при написании кода, который на практике будет писаться статистически незначимым числом людей.

                                                              Only users with full accounts can post comments. Log in, please.