Pull to refresh
74
0
Дмитрий Гукетлев @Yavanosta

User

Send message

Что-то профессор Фортран вспомнился.

Покупая подписку вы платите за то, что вас заставят каждый месяц платить за один и тот же функционал. Зачем делать что-то новое, если вам и так несут денежки каждый месяц? А не будете платить и это отключим.

Вижу что сервис только по подписке - даже не рассматриваю.

Вот свежая драма про "подписочные" сервисы и умный дом из США например.

https://youtu.be/ib1l5CkFmt0?si=0z8PXWlL8QNmzXTm

Звучит это очень загадочно, как и ваши примеры кода.

Извините, но это буквально уже невежливо.


Ваша статья строится на том, что вы изменили сложность алгоритма с квадратичной на линейную. Это основное утверждение которое вы сформулировали в своей статье. Я утверждаю что у вас НЕ изменилась сложность алгоритма т.к. он как был линейным так и остался (если считать за N число файлов).


Вы обосновываете изменение сложности тем, что раньше "был цикл в цикле" а теперь его нет. Я утверждаю что просто сам факт наличия цикла в цикле НЕ делает алгоритм квадратичным. Можно написать цикл в цикле в цикле и алгоритм при этом будет линейным, а можно написать один цикл и он будет квадратичным. Потому что сложность алгоритма это не просто вложенность циклов.


Я вам привел вырожденный пример где искуственно сделал из одного цикла два вложенных без изменений сложности чтобы продемонстрировать тот факт что ваш подход к измерению сложности неверный.


Вот в википедии написано:


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

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


Дальше вы начинаете писать что то про стоимость поддержки и что оптимизация важна. Я просто не понимаю вы мешаете стоимость поддержки с алгоритмической сложностью.


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


Касательно замены push на concat я совершил ошибку что об этом написал. Не потому что то что я сказал неправильно просто теперь вы всё время пытаетесь увести разговор на это, вместо то чтобы обсуждать что в статье допущена ошибка. Если мы придём к согласию относительно статьи я могу разобрать с вами смысл замены push на concat и объяснить почему это может или не может приводить к изменению скорости исполнения (с учётом реализации в v8), но сейчас давайте оставим этот вопрос за скобками, т.к. в реальных условиях вклад этого изменения врятли будет заметен измерением. Либо вы можете разобраться в этом сами если посмотрите первые две лекции курса ссылку на который я отправил выше. При том что ваше изменение вклада не имеет вообще потому что это буквально тот же код.


Кроме того я провёл измерение следующим способом:


git pull https://github.com/coderaiser/putout.git

# коммит с оптимизацией
git checkout 07ced670d1ff03c768844b114f63e70117b15be3
npm i

# Первый прогон отбрасываем чтобы прогрелись все кэши
time npm run lint:fresh

# Делаем три прогона и усредняем
time npm run lint:fresh
time npm run lint:fresh
time npm run lint:fresh

# откатываем коммит с оптимизацией
git revert 07ced670d1ff03c768844b114f63e70117b15be3
npm i

# Первый прогон отбрасываем чтобы прогрелись все кэши
time npm run lint:fresh

# Делаем три прогона и усредняем
time npm run lint:fresh
time npm run lint:fresh
time npm run lint:fresh

Я получил такие результаты.


С оптимизацей
Executed in 36.76 secs
Executed in 37.00 secs
Executed in 36.51 secs
Среднее 36.76


Без оптимизации
Executed in 36.93 secs
Executed in 36.88 secs
Executed in 36.79 secs
Среднее 36.87


Разница 0.11s или 0.3%. При том что разброс между отдельными измерениями вполне доходит до 0.5s я думаю что это можно списать на погрешность. Ни о каких 13% ускорения речи не идёт.

Ну я указал что вам нужно найти. Можете начать с Википедии или курса лекций Яндекса (сложность первые две лекции). То что ваше объяснение проще, ничего не стоит если оно не верное. А оно не верное.

Давайте отбросим рассуждения про push и concat. Разница там будет очень маленькой т.к. v8 оптимизирует push и я не думаю что будет разница заметная на тестах. Я писал про алгоритмическую сложность и сделал пометку про "зависит от реализации". За счёт дополнительной памяти можно сделать push в среднем линейным, если я правильно помню (это разбирается во второй лекции курса ссылку на который я дал).

Давайте вернёмся к главной теме. Ваши алгоритмы до и после оптимизации идентичны. Это изменение не приводит к изменению алгоритмической сложности. Вы можете что-то на это возразить?

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


Смотрите пример. Вам надо обойти массив длиной N. Это можно сделать в цикле:


for (let i = 0; i < arr.length; i++) {
something(arr[i]);
}

Кажется мы оба согласны что это алгоритм линейной сложности.


Дальше смотрите я сделаю так:


const half = arr.length / 2;
for (let i = 0; i < 2; i++) {
    for (let j = half * i; j < half * (i+1); j++) {
      something(arr[j]);
    };
}

Является ли второй пример квадратичным? Ведь в нем есть "цикл в цикле"! Нет там все также линейная сложность. Можно переписать это ещё раз и сделать "цикл в цикле в цикле". Кошмар! Должна быть кубическая! Но нет все ещё остаётся линейная.


Но почему? Количество операций которые мы выполняем не изменилось. Мы проходим по каждому элементу один раз. От того что циклов стало два не изменится ничего. Я даже предположу что современные компиляторы выдадут одинаковый результат для обоих кусков кода.


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


Что касается вашего предложения перепроверить ваши замеры, извините но делать этого я не буду. Ваше предложение похоже на чайник Рассела. Вы высказали некоторое утверждение, я указал вам на то что оно кажется неверным и привел некоторое разумное объяснение. Вы предлагаете мне потратить значительно большее количество времени чем то что вы потратили на написание этой статьи. Извините, но даже не понятно что измерять. Вы сначала сравниваете с мастером, теперь с 17.5.0. Что за проект вы анализировали, не указано. Как прогревали кэши и сколько раз проводили измерения — не указано.


Потом вы сами пишете что да, может стало быстрее из-за того что v8 лучше оптимизирует. А может не стало, а может не лучше.


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

Но в тексте написано прямо противоположное. "сколько данных — столько и операций" это линейная сложность.


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


Пример константной сложности — поиск в массиве. Чтобы получить элемент с номером N надо просто взять смещение по размеру элемента и обратиться к нужному месту в памяти. Поэтому размер массива не имеет значения.


О(1) это константная сложность.

В двух словах идея такая:
имеет горячий код с квадратической сложностью -> делаем замеры -> оптимизируем код до линейной сложности -> делаем замеры -> код стал быстрее и проще в поддержке -> PROFIT

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


Буду благодарен за изминение кода + замеры, а еще мне не до конца понятно использование concat + spread при том, что map возвращает новый массив, и это равнозначно следующему коду:

  1. Это не идентично. Ваш вариант вернёт массив массивов, а мой плоский массив.
  2. Идея в том, что добавляя элементы по одному вы можете попасть на квадратичную сложность. Операция может иметь линейную сложность и соответственно вы можете на каждом цикле попасть на копирование всего существующего массива. concat принимает сразу массивы и склеивает их, по крайней мере копирование будет одно.

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

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


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

Проблема в том, что не понятно из-за чего произошло изменение, это вызывает все вопросы. Совершенно не понятно при чём тут монорепозиторий.

Я прочитал пост несколько раз пытался понять откуда берётся ускорение.


Допустим у нас 5 раннеров и каждый раннер возвращает нам 10 файлов. В первом варианте каждый раннер будет вызван один раз, функция processFile будет вызвана для каждого файла, т.е. 50 раз.


Да тут есть цикл в цикле но это ничего не меняет. Каждый внутренний проходит только по тем файлам что вернул текущий раннер. Т.е. каждый раннер будет вызван один раз и processFile будет вызвана 50 раз.


function process() {
    const results = [];

    for (const run of runners) {
        const files = run();

        for (const file of files) {
            results.push(processFile(file));
        }

     return results;
}

Т.е. нет никакой разницы с


function process() {
    const results = [];

    for (const run of runners) {
        files.push(...run());
    }

    for (const file of files) {
        results.push(processFile(file));
    }
     return results;
}

Тут также каждый раннер вызывается один раз и потом для каждого файла (а их будет 50 штук) будет вызван processFile.


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


Это можно полечить например с помощью чего-то вроде [].concat(...runners.map(r => r()));, тогда хотя бы не будет добавления элементов по одному.


Но главный вопрос, почему же стало быстрее не давал мне покоя и кажется я нашёл ответ. Проводя контрольный замер автор сравнивает мастер+свой патч с некоторой версией v17.5.0. Рискну предположить что разница из-за какого-то другого изменения. А тактов стало меньше потому что автор разделил функцию на три и они просто между ними размазались.


Может быть я понял что-то не так?

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

Однажды мне срочно нужен был телевизор и не было времени ехать за самой дешевой ценой. Прошерстив список из пары десятков конкурентов купил интересующий меня телевизор в Эльдорадо около дома по приемлемой цене, скидка составила порядка 10 тысяч рублей. С учётом того что они скидывали 110% разницы получилась почти самая дешевая цена с маркета.

Я слышал про другую уловку, когда крупная магазин торгует уникальным товаром, уникальность которого заключается в незначительном изменении артикула который вы не можете найти ни в какой другой сети (хотя точно такой же телевизор можете, но с другим артикулом). Но живьём никогда с таким не сталкивался, хотя пользовался этими акциями несколько раз.
Меня интересует немного другой сценарий использования.
1. Есть данные которые 95% времени нужны только на чтение.
2. Скорость чтения и записи не важна
3. Надежность важна
4. Тишина компьютера важна

Допустим у меня есть 2Тб данных и два диска для них — hdd 2Tb и ssd 2Tb. Я хочу использовать их в зеркале. Можно ли настроить систему так чтобы hdd не запускался до тех пор пока не потребуется что-то записать. Да может будет немного медленнее чем читать с hdd и ssd вместе (хотя не думаю) но это в общем-то меня устраивает. Хочется чтобы компьютер не шумел вообще. Все остальное кроме дисков у меня полностью бесшумное.

Можно конечно решить проблему радикально — купить и на вторую часть зеркала ssd но как-то дорого, да и потребности пока нет, места хватает, диски все нормально работают.

Есть ли такая опция?

Ну насколько я могу понять, по обрывочным комментариям ТС, в частности про golang выше, основных проблем он видит две:


  1. В том, что часто используется старая версия PHP видимо имеющая какие-то проблемы с безопасностью (я не в курсе есть ли известные эксплоиты на старые версии)
  2. В том что язык интерпретируемый и залив на сервер PHP файл можно легко получить шелл, что сложнее с компилируемыми языками, где залить файл с кодом недостаточно. Надо как-то запустить свой бинарник и дать ему доступ в сеть.

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


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

Рискну предположить что нисколько. В Германии страховая медицина, так же как в России. Т.е. вы платите процент от зарплаты, а непосредственно за лечение не платите (по крайней мере за основные виды лечения). Плюс она покрывает часть лекарств, если врач выписал соответствующий рецепт вы платите в аптеке только 5 евро, остальное покрывается страховкой.

Пребывание в госпитале «стоит» (т.е. оплачивается из своего кармана) 10 евро в день. Кстати для чего это сделано я так и не понял. Думаю эти 10 евро даже еду которой кормят в больнице не покрывают. Наверное чтобы люди не забывали что вообще то всё не бесплатно.
Вы кажется пытаетесь упростить. Экономического смысла эмиграция действительно почти не имеет. Там где люди больше зарабатывают там больше тратят.

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

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

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

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

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

Но вообще нет решения для всех. Что вы считаете правильным то и правильно для вас.

Я не буду скрывать, что до того как я переехал в Германию мне это решение казалось как минимум очень серьезным, разделяющим всю жизнь на до и после (и это не смотря на то что я много переезжал по России). Но в итоге оказалось что это относительно рядовое решение и защищать тут особо нечего. Можно переехать в другую страну, можно вернуться назад за пару месяцев. Да в этом метании сгорит какая-то крупная сумма денег, придётся оформлять много бумажек, но зато получится опыт, впечатления. А зачем тогда ещё жить? У жизни вообще нет цели, только процесс.
Я почитал дискуссии в других ветках, вы отвечаете с очень сильной защитной позиции. Кажется что очень много людей вокруг осуждают ваше решение. Я просто хотел бы явно проговорить я не пытаюсь вас в чём-то убедить или переубедить. Мой комментарий был просто про мои впечатления. Мы же сидим в комментариях чтобы делиться мнениями :-)

Я искренне считаю что вы поступили правильно и когда переехали в Германию и когда переехали обратно в Россию. Вы получили опыт. Вы получили впечатления. Вы попробовали и осознанно решили что это не для вас. Вы уверены в том что живёте в том месте которое максимально комфортно для вас. Только это дорогого стоит. То что Германия не только сахар понимаешь только переехав в Германию. Это тоже страна со своими особенностями и проблемами.

То что вы поделились опытом отлично в двойне. Я совершенно искренне считаю что вы сделали всё правильно. Приношу прощения если где-то создалось другое впечатление.
Я только Edeka знаю на Hbf видимо ещё один есть :-)
У меня есть сомнение, что доход продавцов изменится если разрешить работать по воскресеньям.

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

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


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

Я уделил целый абзац тому, что для разных людей имеют значение разные вещи. Видимо вам просто не подходит Висбаден.

Я не говорю что вы сделали неправильный выбор и не пытаюсь вас переубедить. Тут вообще не может быть неправильного выбора. Как вы считаете лучше так и правильно для вас. Я просто попытался высказать свою точку зрения тоже.
Германия просто другая. Многие вещи не хуже и не лучше, они просто другие.

Например расскажу свою точку зрения про сервис. Да, всё долго. Да, всё что связано с ручным трудом очень дорого. Да, доставка столика из Икеи за 60 евро стоит сравнимо со столиком, а такси не может себе позволить почти никто (серьезно я не понимаю кто на нём вообще ездит). После Москвы где я вызывал минимум комфорт+ не особо глядя на цену это конечно дико.

Но у этого есть обратная сторона, тут совсем другой темп жизни. Я с ужасом вспоминаю Москву именно из-за темпа жизни. В Москве люди в метро ходят быстро. Едят быстро. Работают много и быстро. Везде принцип делать больше и быстрее или умрёшь с голоду. Также как многие в комментариях я работал с третьего курса, а на шестом (МГТУ) работал фуллтайм 40 часов в неделю. Тут никто не спешит. Заканчиваешь работать во время и спокойно едешь на велосипеде домой. Проводишь время с семьёй.

Да нельзя заказать айфон с доставкой на сегодня, а велосипед мне вообще пришлось ждать 3 недели (и это ещё повезло). Но помните что за каждым удобством и быстрым сервисом который вам нравится стоит кто-то кто это делает. За доставкой продуктов 24 часа в сутки за 15 минут стоят курьеры работающие круглосуточно и возможно не видящие семью неделями. И где-то в этом цикле, скорее всего, тем или иным образом, крутитесь и вы, ведь вы же не только клиент, но и как минимум 8 часов в день сотрудник. А в Мюнхене (1.5 миллиона человек население) в воскресенье работает только три продуктовых магазина и один из них в аэропорту. И работать в воскресенье не разрешает закон, хотя сети вроде как были бы рады открыться хоть круглосуточно. Просто все решили что лучше каждый будет немного страдать от не такого классного сервиса, но зато и сам будет жить свободнее и в конечном счёте лучше.

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

Да ждать врача, если у вас нет ничего срочного, 3-4 недели, но так ведь у вас и нет ничего срочного. Запишитесь и ждите. Просто люди живут с другим горизонтом планирования. Если ты знаешь, что тебе надо два раза в год ходить к зубному, то просто записываешься сразу на апрель и ноябрь следующего года. А если что-то срочное то в госпитале помогут. Мне сделали экстренную операцию меньше чем через сутки после обращения в госпиталь. Качество медицины точно не хуже бесплатной медицины в Москве. И плановой и экстренной, мы успели попользоваться обеими.

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

У нас есть старая семейная история. Много лет назад мы приехали в отпуск в Египет, ещё когда это было можно. Вылетали в субботу с утра, после рабочей недели. Весь день перелёт, переезд на автобусе, заселение и вот приходим в ресторан, а там шведский стол. Мы набрали какой-то еды, соков и (как я потом оценил) минут за 5-7 всё это в себя покидали и собираемся куда-то идти дальше что-то делать. Глядя на это не выдерживает официант, приносит нам два бокала вина, показывает на море, на звёзды и говорит (по русски) «не надо бежать, сядь, посиди отдохни». Он потом рассказал что тех кто приехал из Москвы видно за версту именно по темпу с которым они всё делают. Для меня Германия это такое «не надо бежать» растянутое во времени в бесконечность.
Code Review это процедура когда изменения прежде чем попасть в мастер оформляется в пакет (Pull Request, Merge Request, Change List) и проходит проверку одним или несколькими другими программистами этого же проекта.

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

Можете сами попробовать в почти любом опенсорсном проекте на гитхабе. Чаще всего там есть список задач отмеченных чем-то вроде «Good first task» — несложные задачи которые позволяет разобраться в проекте. Исправляете ошибку\добавляете функционал и делаете ПР. Ждёте прохождения ревью, исправляете недочёты и ваш код в мастере.
1
23 ...

Information

Rating
Does not participate
Location
Балашиха, Москва и Московская обл., Россия
Date of birth
Registered
Activity