Фантастическая скорость работы slice связана с оптимизацией Copy-on-Write. Эта оптимизация, при которой копирование больших данных откладывается до тех пор, пока одна из копий не будет изменена. То есть, по сути, создается не копия массива, а новая ссылка на память, в которой хранится ссылка на исходный массив. И лишь в момент изменения нового массива происходит фактическое копирование. Чтобы в этом убедиться, можно в цикле со slice после копирования производить операцию, изменяющую новый массив (например, push). Тогда вся магия исчезает и slice начинает работать не быстрее map или for.
@davidhayrapetyan7039Ай бұрын
а можно пожалуйста пример кода ? изменяя массив после копирования (10000 элементов) у меня slice (2s) а map(2.7s) chatGPT объясняет что в slice не передается функция и оно не вызывается для каждого элемента по этому он быстрее
@KadochnikovKАй бұрын
@@davidhayrapetyan7039 ну 2 секунды и 2,7 секунд это не такая большая разница. Slice, конечно, быстрее, чем map. Но не в тысячи раз.
@ВиталийБоднар-е1я2 ай бұрын
Алексей в первом методе создания копии использовал push, что для данной задачи может быть оптимизированно, если написать это немного иначе, то результат будет получше: for (let i = 0; i < 100000; i++) { const m = new Array(array.length) for (let k = 0; k < array.length; k++) m[k] = array[k] } Просто push() как будто добавляет в оригинальный массив элементы изменяя его длину, но на самом деле, это не совсем правда, при работе этого метода JS периодически создаёт новые массивы с удвоенной длиной когда длины нынешнего массива не хватает (JS изначально создаёт массивы с запасом длины). При этом приходится копировать элементы со старого массива в новый и запускать garbage collection что затратно. Если изначально создать массив нужной длины то время сократится вдвое. Но конечно slice() тут всё равно вне конкуренции. И видео всё равно интересное и познавательное.
@itgid2 ай бұрын
@@ВиталийБоднар-е1я огромное спасибо. Действительно не подумал по индексу. Насколько быстрее получается у вас?
@SerzhNesterukАй бұрын
Спасибо за уместное замечание. Хотя тут есть ещё вторая сторона медали. Мы конечно экономим на реалокациях массива в памяти. Но вот массивы созданные через конструктор Array (с указанием длины) определяются рантаймом V8 как разреженные. И при дальнейшей работе с этими массивами возможна ощутимая просадка производительности. Поэтому поверхносное клонирование массива лучше таки делать через slice или даже через spread (как ни странно).
@ВиталийБоднар-е1яАй бұрын
@@itgid не намного - в 2 раза быстрее чем при использовании push()
@KadochnikovKАй бұрын
Чтобы спред опреатор в браузере работал быстрее в таких условиях, его можно использовать в таком виде - Array(arr.length).fill(...arr). Да, скорость все еще будет ниже чем у slice, но не в десятки тысяч раз, а, всего лишь, в сотни. А при однократном копировании одного огромного массива на 50 000 000 элементов разница и вовсе отсутствует, только в этом случае использовать нужно [...arr], иначе произойдет переполнение стека.
@AlexGabberАй бұрын
Смущает слайз, а не помещает ли он просто ссылку в переменную, вместо копирования? Для массива с примитивными данными подходит все, для глубокой структуры только стрингифай парс и структуредклон (жаль не был разобран)
@urakendАй бұрын
Это легко проверить.Увеличить объем массива и сравнить время.
@AlexGabberАй бұрын
@@urakend а причем тут время? вопрос создает ли клон слайз или просто ссылается на текущий объект произведя нулевую мутацию
@urakendАй бұрын
@@AlexGabber ,а притом,что во втором случае оно не измениться...
@xthemeyАй бұрын
Самое интересное, что результаты для браузера и для Node js отличаются) //Node Js 3408 loop for 3339 loop while 1 spread 1 slice 1998 map 3331 filter 2 Array.from 25202 JSON.parse(JSON.stringify) 3 concat 1474 copy by index to new Array() /// 24624 structuredClone 184778 Object.assign // Browser 2485 'loop for' 2455 'loop while' 21746 'spread' 3 'slice' 3870 'map' 2864 'filter' 16841 'Array.from' 16796 'JSON.parse(JSON.stringify)' 2 'concat' 622 'copy by index to new Array()' /// 15350 'structuredClone' 140473 'Object.assign'
@swayokАй бұрын
Всегда использовал slice вместо новомодных свистелок и, видимо, не зря. Но вообще странно что Array.from() такой медленный.
@zestlife57922 ай бұрын
Concat?
@ГаляКравченко-у2ш2 ай бұрын
Я взагалі в шоці 😮
@ИванГоденов-и7дАй бұрын
Для чистоты эксперимента нужно движок JS было указать и его версию, т.к. в других движках могут присутствовать свои оптимизации и результат может кардинально отличаться. Например, в V8 есть оптимизации для цикла for и while для большого количества итераций. В том же V8 итерационные методы массивов базируется на reducer-е, т.е., поэтому их производительность будет примерно одинаковой. И очень многое также зависит от того как движок JS работает с памятью при создании и изменении массивов. Одно дело создавать массив с числами или строками без дырок и совершенно другой случай, когда в массиве встречаются дырки или данные другого типа. В спецификации для этих случаев создаются вообще разные виды массивов. И работа с ними будет существенно отличаться.
@itgidАй бұрын
Увы чистого эксперимента не получится. Если же провести эксперимент с научной точностью то данное видео просто смотреть никто не будет. Повторял и буду повторять - есть фреймворк PHP Yii2. Его разрабочтик записывает видео длинной 3-4 часа наполненные очень крутой информацией, бесценной. У него 100-150 просмотров за много лет. Нужно понимать что даже shorts нарезанный с марвел набирает больше чем видео по программированию, поэтому приходится работать в сжатых рамках на грани "попса-программирование-популизм".
@Nine_Tails2 ай бұрын
forEach то же, что и for?
@16540452 ай бұрын
вот у меня на 100 000. Slice: 0.40 ms Spread: 11.80 ms Array.from: 6.10 ms Concat: 0.60 ms For Loop: 44.50 ms
@_AnthonyD_2 ай бұрын
А почему так происходит-то? Компилятор лучше оптимизирован для slice? или в чем дело?
@KadochnikovKАй бұрын
Фантастическая скорость работы slice связана с оптимизацией Copy-on-Write. Эта оптимизация, при которой копирование больших данных откладывается до тех пор, пока одна из копий не будет изменена. То есть, по сути, создается не копия массива, а новая ссылка на память, в которой хранится ссылка на исходный массив. И лишь в момент изменения нового массива происходит фактическое копирование. Чтобы в этом убедиться, можно в цикле со slice после копирования производить операцию, изменяющую массив (например, push). Тогда вся магия исчезает и slice начинает работать не быстрее map или for.
@Tar2gaАй бұрын
зачем в цикле на 10 тысяч раз делать map, filter, spread и т.д.?
@SerzhNesterukАй бұрын
Это очень правильный вопрос! ☝️ JIT-компиляторы современных JS-рантаймов могут оптимизировать выполнение некоторых сценариев при их многократном выполнении (например, несколько тысяч раз). Такие оптимизации, как loop unrolling (развертка циклов) или dead code elimination (удаление мертвого кода), могут существенно влиять на результаты бенчмарков или даже заметно их искажать. Использование литеральной записи массива вместо генерации массива со случайными данными также может добавить искажения в результаты бенчмарков. Литеральные массивы имеют фиксированную структуру, и их поведение более предсказуемо с точки зрения JIT-компилятора, что может сделать результаты менее репрезентативными для реальных сценариев с динамически изменяющимися данными. Таким образом, хотя результаты бенчмарков довольно интересны, но без учета таких факторов, как уровень оптимизации кода, прогрев JIT или предсказуемость структуры данных, их точность может быть сомнительной и не в полной мере отражать реальную производительность.
@itgidАй бұрын
Потому что одинарный запуск такого кода, учитывая современные скорости, не даст понять разницу. Нужно будет увеличивать массив. Задача стоит не провести академический эксперимент, а обратить внимание на разницу скоростей и заставить людей задуматься над тем, что под капотом у методовов, как они работают.
@АлексейСоколов-у3кАй бұрын
на 3 млн эл [...arr] заняло 521мс, на slice 125мс
@1SkinneR111Ай бұрын
У меня так получилось: slice_____________________________________________________2 concat___________________________________________________2 loop while (C изначально заданной длиной массива) __517 loop for (C изначально заданной длиной массива)____ 520 map____________________________________________________893 filter___________________________________________________1658 reduce_________________________________________________1753 loop for (через push())_________________________________1762 Array.from()____________________________________________11117 spread_________________________________________________15095 JSON.parse(JSON.stringify())___________________________15617 structuredClone________________________________________16090