$30 off During Our Annual Pro Sale. View Details »

Fast by default: everyday algorithmic thinking for developers [RU]

Fast by default: everyday algorithmic thinking for developers [RU]

Vladimir Agafonkin

October 06, 2018
Tweet

More Decks by Vladimir Agafonkin

Other Decks in Programming

Transcript

  1. Vladimir Agafonkin
    ⚡Fast by default:

    everyday algorithmic thinking
    2018

    View Slide

  2. rain.in.ua

    View Slide

  3. View Slide

  4. View Slide

  5. View Slide

  6. View Slide

  7. одержимый
    скоростью кода

    View Slide

  8. ❤❤❤
    open source

    View Slide

  9. 1. Найти узкую задачу
    2. ⚡ Создать для нее самую быструю и
    простую в мире JavaScript-библиотеку
    3. Перейти к пункту №1

    View Slide

  10. Leaflet, mapbox-gl-js, mapbox-gl-native, earcut, earcut.hpp,
    rbush, rbush-knn, kdbush, kdbush.hpp, geokdbush,
    flatbush, geoflatbush, concaveman, supercluster,
    supercluster.hpp, dobbyscan, delaunator, delaunator-rs,
    d3-delaunay, linematch, lineclip, pixelmatch, simplify-js,
    cheap-ruler, polylabel, tinyqueue, flatqueue, tile-cover,
    which-polygon, quickselect, simple-statistics, tiny-sdf,
    geojson-vt, potpack, geojson-vt-cpp, geobuf, pbf, tile-
    reduce, geojson.hpp, geometry.hpp, tile-decorator, mbtiles-
    extracts, webgl-wind, suncalc, flamebearer, simpleheat,
    binary-split, magic-string, polysnap, rollup, sourcemap-codec

    View Slide

  11. github.com/mapbox/delaunator

    View Slide

  12. github.com/d3/d3-delaunay

    View Slide

  13. 1.delaunay: 150s
    2.delaunay-fast: 117s
    3.faster-delaunay: 5s
    4.delaunator: 1s⚡
    5.delaunator-cpp: 0.9s
    6.delaunator-rs: 0.9s
    триангуляция 1 миллиона точек в JS

    View Slide

  14. mapbox/earcut (JS)
    mapbox/earcut.hpp (C++)

    View Slide

  15. пространственные индексы

    View Slide

  16. github.com/mourner/rbush
    github.com/mourner/kdbush
    github.com/mourner/flatbush
    github.com/mourner/rbush-knn
    github.com/mourner/geokdbush
    github.com/mourner/geoflatbush

    View Slide

  17. mapbox/supercluster (JS)
    mapbox/supercluter-hpp (C++)

    View Slide

  18. mapbox/supercluster (JS)
    mapbox/supercluter-hpp (C++)

    View Slide

  19. ~
    mapbox/geojson-vt (JS)
    mapbox/geojson-vt-cpp (C++)

    View Slide

  20. github.com/mapbox/webgl-wind

    View Slide

  21. github.com/mapbox/potpack

    View Slide

  22. mapbox/pixelmatch (JS)
    mapbox/pixelmatch-cpp (C++)

    View Slide

  23. View Slide

  24. математическое
    образование? %

    View Slide

  25. View Slide

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

    View Slide

  27. Владимир Агафонкин
    Идиотское введение в алгоритмы
    2018

    View Slide

  28. зачем понимать
    алгоритмы?

    View Slide

  29. View Slide

  30. 99% проблем
    с быстродействием —
    алгоритмического характера

    View Slide

  31. медленный код:
    код, выполняющий
    лишнюю работу

    View Slide

  32. View Slide

  33. алгоритмическое
    мышление:
    искусство отлынивать
    от лишней работы (в коде)

    View Slide

  34. приложение
    фреймворки

    View Slide

  35. View Slide

  36. rollup/rollup#2062
    rollup: map = magicString.generateMap()
    rollup: obj = decode(map)

    View Slide

  37. rollup/rollup#2062
    rollup: map = magicString.generateMap()
    magic-string: ...
    map = encode(obj)
    rollup: obj = decode(map)

    View Slide

  38. rollup/rollup#2062
    rollup: map = magicString.generateDecodedMap()
    magic-string: map = encode(obj)
    rollup: obj = decode(map)
    source map’ы на 40% быстрее

    View Slide

  39. требует алгоритмического мышления
    1. найти узкие места
    2. выяснить, почему они медленные
    3. оптимизировать
    оптимизация:

    View Slide

  40. View Slide

  41. O(1)
    O(log n)
    O(n)
    O(n log n)
    O(n2)
    O(n3)

    View Slide

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

    View Slide

  43. array[0] + array[1];
    O(1) — моментально

    View Slide

  44. O(n) — подозрительно
    for (const item of array) {
    sum += item;
    }

    View Slide

  45. O(n2) — тормозное говно
    for (let i = 0, n = array.length; i < n; i++) {
    for (let j = i + 1; j < n; j++) {
    sum += array[i] + array[j];
    }
    }

    View Slide

  46. function foo(array) {
    for (const item of array) {
    array[array.indexOf(item)] = item + 10;
    }
    }
    O(n2) — тормозное говно

    View Slide

  47. function foo(array) {
    for (const item of array) {
    bar(array, item);
    }
    }
    function bar(array, item) {
    array[array.indexOf(item)] = item + 10;
    }
    O(n2) — тормозное говно

    View Slide

  48. accidentallyquadratic.tumblr.com

    View Slide

  49. O(n3) — невыносимо, выкинуть нафиг
    for (let i = 0, n = array.length; i < n; i++) {
    for (let j = i + 1; j < n; j++) {
    for (let k = j + 1; k < n; k++) {
    sum += array[i] + array[j];
    }
    }
    }

    View Slide

  50. 1. O(1) — моментально
    2. O(n) — подозрительно
    3. O(n2) — тормозное говно
    4. O(n3) — выкинуть нафиг

    View Slide

  51. 1. O(1) — 1
    2. O(n) — 1000
    3. O(n2) — 1,000,000
    4. O(n3) — 1,000,000,000
    (n = 1000)

    View Slide

  52. чорти б мене побрали!!!
    хай йому грець!!
    дідько!
    if (j < 0) {
    if (triangles.length === 0) triangles.push([i]);
    return;
    }
    for (let n = triangles.length, a = 0; a < n; ++a) {
    let sa = triangles[a];
    if (sa[0] === j) {
    for (let b = a + 1; b < n; ++b) {
    let sb = triangles[b];
    if (sb[sb.length - 1] === i) {
    triangles.splice(b, 1);
    triangles[a] = sa = sb.concat(sa);
    return;
    }
    }
    sa.unshift(i);
    return;
    }
    d3/d3-delaunay#23

    View Slide

  53. array.indexOf
    array.lastIndexOf
    array.splice
    array.includes
    array.reverse
    array.every
    Object.values
    array.find
    array.some
    array.findIndex
    array.reduce
    array.reduceRight
    array.some
    Object.keys
    O(n) — подозрительно

    View Slide

  54. View Slide

  55. array.slice
    array.concat
    array.map
    array.filter
    str.split
    подозрительные аллокации

    View Slide

  56. a.slice().concat(b).map(foo)
    .filter(bar).reduce(bla, 0);
    выделить память и
    сразу выкинуть (4 раза)

    View Slide

  57. for (const b of items) {
    a.slice().concat(b).map(foo)
    .filter(bar).reduce(bla, 0);
    }
    выделить память и
    сразу выкинуть (4 раза)

    View Slide

  58. имьютабилити!
    реактивность!
    функциональное
    программирование!
    чертовы
    аллокации

    View Slide

  59. JIT-оптимизатор в
    JS-движках не всегда
    понимает, чего вы хотите

    View Slide

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

    View Slide

  61. Rich-Harris/sourcemap-codec#71
    const lines = input.split(';');
    for (const line of lines) {
    const segments = line.split(',');
    for (const segment of segments) {
    const decoded = decode(segment);
    for (const i of decoded) {
    ...
    }
    }
    }

    View Slide

  62. Rich-Harris/sourcemap-codec#71
    for (let i = 0; i < input.length; i++) {
    const c = input.charCodeAt(i);
    if (c === 44) { // ","
    ...
    } else if (c === 59) { // ";"
    ...
    в три раза быстрее

    View Slide

  63. View Slide

  64. O(1) O(n)
    O(log n)
    O(log n) — очень быстро

    View Slide

  65. 1 1,000,000
    20
    O(log n) — очень быстро

    View Slide

  66. бинарный поиск
    o(log n)

    View Slide

  67. View Slide

  68. View Slide

  69. View Slide

  70. View Slide

  71. View Slide

  72. View Slide

  73. rollup/rollup#2228

    в 40 раз быстрее

    View Slide

  74. 1. O(n) → O(log n)
    2. O(n log n) → O(n)
    3. O(n2) → O(n log n)
    4. O(n3) — выкинуть
    алгоритмическая оптимизация:

    View Slide

  75. медленно медленно медленно
    алгоритмическая оптимизация:

    View Slide

  76. организовать данные
    алгоритмическая оптимизация:

    View Slide

  77. алгоритмическая оптимизация:
    сделать больше в начале,

    чтобы делать меньше

    каждый следующий раз

    View Slide

  78. структуры данных:
    как организорвать данные
    для быстрого поиска и
    обновления

    View Slide

  79. • hash map
    • hash set
    • binary search tree
    • priority heap
    • linked list
    • interval tree
    • grid
    • r-tree
    • quadtree
    • kd-tree
    структуры данных:

    View Slide

  80. отсортированный массив
    o(n log n)
    ❤ любимая структура данных:

    View Slide

  81. отсортировать вокруг элемента,
    чтобы все слева были меньше
    o(n)
    github.com/mourner/quickselect
    39, 28, 28, 33, 21, 12, 22, 50, 53, 56, 59, 65, 90, 77, 95

    View Slide

  82. github.com/mourner/kdbush

    View Slide

  83. priority queue:
    push: o(1)
    top: o(1)
    pop: o(log n)
    github.com/mourner/tinyqueue
    github.com/mourner/flatqueue

    View Slide

  84. {
    '1': 10,
    '2': 20,
    '3': 30
    };
    {
    '0': 10,
    '1': 20,
    ‘2': 30
    };
    HashTable Array
    [10, 20, 30];

    View Slide

  85. istanbuljs/istanbul-lib-instrument#22
    {
    '1': 10,
    '2': 20,
    '3': 30
    };
    {
    '0': 10,
    '1': 20,
    ‘2': 30
    };
    в 15 раз быстрее

    View Slide

  86. все необходимое уже
    изобрели до вас*
    *но реализовали через ж

    View Slide

  87. как я читаю

    научные публикации

    и прилагаемый код

    View Slide

  88. 1. думайте, как оно работает

    2. не бойтесь лезть в чужой код +

    3. не бойтесь изобретать велосипеды

    4. участвуйте в open source ❤

    5. постоянно упрощайте

    6. практикуйте оптимизацию , и вы научитесь
    писать код, который сразу работает быстро

    View Slide

  89. спасибо
    agafonkin.com

    View Slide