Комментарии 468
А ещё можно было ба написать версию для тензор ядер… Было бы вообще огонь по скорости.
Когда процессоры будут удваивать скорость лет за 10~15, варианты «работает в 2 раза медленнее, зато разрабатывать на этом в 1.2 раза быстрее» больше не проканают, будет спрос на более быструю реализацию устоявшихся парадигм — и вот тут начнут оптимизировать.
В то время как на мобилках более чем на порядок.
А до предела однопоточной производительности ещё далеко.
За последние 10 лет
Кривая роста производительности у мобильных чипов сильно другая. Можно объяснить это эффектом «низкой базы», но A4 @ 800MHz десятого года это всё же процессор, который исправно выполнял все «смартфонные» функции.
Прогресс быстро шёл из-за того, что на мобильном рынке новая микроархитектура и новый техпроцесс стабильно появляются каждый год, в отличие от :)
Для bsearch если у Вас и 1е8 элементов, то это лишь ~26 операций будет в худшем случае, такое не надо параллелить. Если вы часто ищете — надо параллелить чтение(bsearch) и блокировать запись (вставка нового элемента). Если блокировки частые и мешают работе, можно как-то пул вставок делать и время от вермени сливать массивы.
С aes-cbc таже песня, алгоритм использует данные на предыдущем шаге, если у вас данные огромной длинны — то тут я не знаю как можно распараллелить, если у вас много поменьше — то это норм распределить на потоки.
Не выстрелило — не потратили много времени на работу, которая никуда не нужна. Плюс есть даже такой термин «преждевременная оптимизация». «преждевременная оптимизация — корень всех зол» — Дональд Кнут»
Другое дело спец вычисления, но их обычно и пишут сразу правильно и на всяких фортранах, лиспах… А если надо ещё быстрее — есть ASIC, например сети — те же циско часто раньше роутинг на асиках делали, получая очень быструю работу.
есть популярность, начинаем оптимизироватьЧего по факту не происходит. Исходят из того, что раз оно популярно то и оптимизировать незачем, лучше потратить деньги на новые фичи из за которых будет лагать ещё больше.
Эта цитата выдрана из контекста.
The real problem is that programmers have spent far too much time worrying about efficiency in the wrong places and at the wrong times; premature optimization is the root of all evil (or at least most of it) in programming.
We shouldn't be penny wise and pound foolish, nor should we always think of efficiency in terms of so many percent gained or lost in total running time or space. When we buy a car, many of us are almost oblivious to a difference of $50 or $100 in its price, while we might make a special trip to a particular store in order to buy a 50 cent item for only 25 cents. My point is that there is a time and place for efficiency; I have discussed its proper role in my paper on structured programming, which appears in the current issue of Computing Surveys
Конечно нет, зачем это делать, если труд разрабов дороже железа до определенного момента. Как только это иначе и заметили — сразу начинают оптимизировать. Не знаю что у Вас по факту не происходит. Да, было бы приятно, если бы пользователи какой-то ОС прямо сейчас получили прирост скорости в 200%. Но если в случае майрософт это будет стоить пару сотен жизней человеко работы — то нет, спасибо. Все это люди которые чет вперед двигают, и фичи, и безопасность и тд. Если бизнес у которого полно денег будет и на эти задачи забирать людей которые чет умеет, то на остальные задачи ресурсов не хватит, и энтузиазма отказаться от денег. А ведь там есть область к медицине близкая, строительство и тд.
И что Вам даст это ускорение, вот один продукт взять — Винда ускорила, все классно, но через время опять фреймворки и пайтоны всякие/js уперлись в потолок по железу, и все. Если все будут оптимизацию в главный угол ставить — то это опять же куча человеко-часов непонятно на что.
Сейчас вводится техпроцесс на 5 нм для производства процессоров. В 2022 году будет 2 или 3 нм. В 2024 — 1. В 2026 — .5, в 2028 — .25 — и это предел, это размер атома кремния. Не получится сделать транзистор меньше атома.
Ну через многоядерность и параллелизацию что-то получится. Ну ещё площадь кристалла можно увеличить… но всё. В обозримое время мы упрёмся в ограничение производительности железа.
Будут ли к тому времени распространены квантовые компьютеры и как они будут программироваться — вопрос.
Как видите, тут маркетологи, привязавшись к размерам ячейки памяти, обманули сами себя, и теперь вынуждены озвучивать цифру больше, чем могли бы. На самом деле, конечно, в условиях принципиального изменения структуры транзистора и ожидания пользователей услышать какую-то метрику, использование метрики, отражающей плотность упаковки, было, наверное, единственно верным решением, и маркетологи в конечном счете оказались правы, хоть это и приводит иногда к забавным ситуациям, когда одни и те же проектные нормы в разных компаниях называют по-разному. Например, читая новости о том, что TSMC уже запустила 7 нм, а Intel опять задерживает начало производства 10 нм, стоит помнить о том, что 7 нм TSMC и 10 нм Intel — это на самом деле одни и те же проектные нормы с точки зрения и плотности упаковки, и размеров отдельных транзисторов.
Проектные нормы в микроэлектронике: где на самом деле 7 нанометров в технологии 7 нм?
Но тот же python с развитием jit-компиляции (pypy, numbaJIT) и добавлением опциональной типизации — возможно, ещё долгое время можно будет выжимать из ускорения интерпритатора и JIT-компиляции. ( даже если не появится террагерцевых процессоров, квантовых компьютеров оптических вычислений и классический закон Мура встанет )
Понятно, что статически типизированные языки имеют фундаментальный бонус в скорости.
Неочевидно, обоснуйте свой тезис.
Как я себе вижу: компилятор может оптимизировать некоторые вещи, зная тип данных (
т.е. если функции на вход всегда приходит массив int'ов — оптимизировать проще, чем если это может быть int, float, строка, или вообще разные кастомные классы, для которых определено сложение друг с другом и деление на int. ( понятно, что такое можно написать и для статически типизированного языка, но если мы ищем среднее арифметическое массива интов [например, средняя зарплата], то у компилятора/интерпретатоора вообще не будет шансов из логики понять, что, например, строк там не будет. ( и и я не знаю динамически типизированных языков, где программист сможет это явно указать [python type hints — не влияют на оптимизацию, numba — статически типизирована, pypy — будет оптимизировать только при многократном вызове с интами])
)
Из языков ровно так работает, например, julia — причём явным образом типы указывать не требуется (но можно).
Numba в питоне тоже, конечно, никак не статически типизирована — до выполнения программы типы аргументов могут быть неизвестны.
Julia, например, компилирует в такое:
> f(a, b) = a / b
> @code_native f(1.0, 2.0) # float
# выдаёт ассемблерный код:
# vdivsd %xmm1, %xmm0, %xmm0
# retq
> @code_native f(1, 2) # int
# vcvtsi2sd %rdi, %xmm0, %xmm0
# vcvtsi2sd %rsi, %xmm1, %xmm1
# vdivsd %xmm1, %xmm0, %xmm0
# retq
> @code_native f(big"1.0", 2.0) # bigfloat - вызов соответствующего метода
# pushq %rax
# movabsq $"/", %rax
# callq *%rax
# popq %rcx
# retq
> f("abc", 1) # строки делить нельзя
# MethodError: no method matching /(::String, ::Int64)
Эту функцию, конечно, можно использовать и внутри других функций
function g(x, b)
res = 0.0
for a in x
res += f(a, b)
end
return res
end
> a = rand(100)
> @code_native g(a, 2.0)
# movq 8(%rdi), %rax
# testq %rax, %rax
# jle L74
# movq (%rdi), %rcx
# vmovsd (%rcx), %xmm1 # xmm1 = mem[0],zero
# vdivsd %xmm0, %xmm1, %xmm1
# vxorpd %xmm2, %xmm2, %xmm2
# vaddsd %xmm2, %xmm1, %xmm1
# cmpq $1, %rax
# je L69
# movl $1, %edx
# nopw (%rax,%rax)
# L48:
# vmovsd (%rcx,%rdx,8), %xmm2 # xmm2 = mem[0],zero
# vdivsd %xmm0, %xmm2, %xmm2
# vaddsd %xmm2, %xmm1, %xmm1
# incq %rdx
# cmpq %rax, %rdx
# jb L48
# L69:
# vmovapd %xmm1, %xmm0
# retq
# L74:
# vxorps %xmm1, %xmm1, %xmm1
# vmovaps %xmm1, %xmm0
# retq
Как видно, единственный оверхед здесь после запуска — один раз скомпилировать функцию для каждого требуемого типа аргументов. Затем выполнение идёт без замедлений относительно нативного кода.
При этом типизация динамическая, и можно составить такую функцию:
h(a) = f(rand(Bool) ? big"1.0" : 1.0, a)
Здесь в машинном коде появляется проверка типа при запуске f, и в зависимости от него запускается либо одна либо другая (скомпилированная, часто даже заинлайненная) её версия.
В питоне нумба, как я писал, тоже по сути динамически типизированная — ведь статических типов в нём в принципе нет.
@numba.njit
def g(x, b):
res = 0.
for a in x:
res += a / b
return res
a1 = np.random.rand(100)
a2 = np.random.rand(100).astype(int)
g(a1 if np.random.rand() > 0.5 else a2, 2.0)
Тип аргумента не известен до выполнения, что никак не мешает компилировать функцию в соответствующий момент. Просто в питоне это работает для весьма ограниченного набора возможностей языка (то, что поддерживается нумбой), а джулия компилирует любой код в машинный перед выполнением, в том числе между библиотеками и пользовательскими типами.
Как видно, единственный оверхед здесь после запуска — один раз скомпилировать функцию для каждого требуемого типа аргументов.
А какой требуемый тип? По вашим примерам ничего не видно, т.к. не показан код, который вызывает эти функции и выясняет, есть ли уже откомпилированная и нужно ли jit-компилировать ещё одну. Оверхед, по сравнению со статической компиляцией именно там.
Затем выполнение идёт без замедлений относительно нативного кода.
Доказательства?
@code_native f(1, 2) # int
vcvtsi2sd %rdi, %xmm0, %xmm0
# vcvtsi2sd %rsi, %xmm1, %xmm1
# vdivsd %xmm1, %xmm0, %xmm0
# retq
Ага, «инт». (╯°□°)╯︵ ┻━┻
По вашим примерам ничего не видно, т.к. не показан код, который вызывает эти функции
Весь код показан — просто открываете REPL джулии и вводите ровно то, что в моём комментарии, те строки которые не с # начинаются. То, что с # в начале — это будет вывод. Можно и в скрипт запихать конечно, только явным образом print'ы проставить.
Больше кода никакого и нет, если конечно вы не имеете в виду реализацию самого компилятора или что-то подобное.
не показан код, который вызывает эти функции
Итак, вызывающий код — это просто f(1, 2), g(a, 2.0) и т.п.
Как видно, единственный оверхед здесь после запуска — один раз скомпилировать функцию для каждого требуемого типа аргументов.
А какой требуемый тип?
Может я не очень вас понял, но требуемый тип — это просто тип, с которым нужно скомпилировать функцию. Есть вызов f(1, 1) — компилируем f(::Int, ::Int); есть f(1.0, 1.0) — это f(::Float, ::Float), и т.д. Если с такими типами уже компилировали — ничего не делаем, просто вызываем (или инлайним) имеющуюся.
Ага, «инт»
Да, возможно я не уточнил, т.к. считал очевидным — какой тип имеют литералы. 1 и 2 — типа Int64, поэтому f(1, 2) вызывает f(::Int, ::Int). 1.0, 2.0 — это Float64.
Затем выполнение идёт без замедлений относительно нативного кода.
Доказательства?
Если брать приведённый мой пример функции f и её вызова в g — то там же приведён ассемблерный код, который будет выполняться при дальнейших вызовах с теми типами. При выполнении этого кода уже не важно, когда он появился — заранее или во время выполнения — скорость будет такая же. С чего вообще по-другому может быть?
Например, предложенный в моём предыдущем комментарии вызов g(a, 2.0) у меня на лаптопе выполняется за ~70 ns. Сравнивать с C/C++ лениво, но для последовательных делений и сложений по 100 раз время вполне соответствует ожидаемому от нативного кода.
При выполнении этого кода уже не важно, когда он появился — заранее или во время выполнения — скорость будет такая же. С чего вообще по-другому может быть?Даже ели допустить, что Julia в runtime'е выполняет настолько качественную оптимизацию насколько возможно (что вряд ли, так как это занимает время) — инлайнинг, к примеру, в такой модели совершенно неприменим. Да и само переключение компиляция/выполнение бесплатно не проходит.
инлайнинг, к примеру, в такой модели совершенно неприменим
Не знаю, откуда такое мнение. Ведь прямо в комментарии выше, где я привожу пример выдаваемого ассемблерного кода, показан инлайнинг! А именно, функция f вставлена в g — никакого дополнительного вызова не происходит.
Даже ели допустить, что Julia в runtime'е выполняет настолько качественную оптимизацию насколько возможно (что вряд ли, так как это занимает время)
…
Да и само переключение компиляция/выполнение бесплатно не проходит.
Не вижу никакой проблемы проводить качественную оптимизацию во время выполнения программы, перед первым запуском каждой функции с новыми типами аргументов. Как я и писал, эта компиляция — единственный оверхед во время работы, но он случается только один раз на каждую комбинацию <функция, типы аргументов>.
Не знаю, откуда такое мнение.Ну допустим Вы наткнулись на вызов функции и захотели его заинлайнить — как Вы это сделаете, если код функции, в которую нужно инлайнить, уже готов (это ведь он выполняется сейчас)? Единственный способ — вставить код с помощью memcpy, но уж лучше тогда не-inline вызов использовать.
Ага, нашел Ваш пример. ОК, есть инлайнинг, но видимо тогда все дерево вызовов скомпилировано за раз, а не по одной функции, как Вы говорите. Ассемблер, кстати, странновато выглядит.
Не вижу никакой проблемы проводить качественную оптимизацию во время выполнения программыДело в том, что качественная оптимизация использует данные обо всей программе, а не об одной конкретной функции. Например, если бы в Вашем примере было целочисленное деление — хороший оптимизатор бы заметил, что второй параметр всегда константный, и заменил бы его на умножение на константу. А компиляция по одной функции такого не сделает, откуда ей об этом знать?
Как я и писал, эта компиляция — единственный оверхед во время работыАга, а как на счет кэша скомпилированных функций? Перед каждым вызовом будьте добры сделать лукап, ну и апдейт кэша после компиляции, если вхождение не было найдено.
Ну допустим Вы наткнулись на вызов функции и захотели его заинлайнить — как Вы это сделаете, если код функции, в которую нужно инлайнить, уже готов
Как именно это технически реализовано — не разбирался и не знаю, могу только предполагать. Видимо, когда вызывается функция с конкретными типами аргументов, проводится некий анализ и вызываемых из неё функций — если они «простые», то инлайнятся.
качественная оптимизация использует данные обо всей программе, а не об одной конкретной функции.
…
второй параметр всегда константный, и заменил бы его на умножение на константу
Опять же, детали реализации я не знаю, но constant propagation в джулии давно завезли. Весьма вероятно, что он менее полный по сравнению с условным Си, просто из-за возраста языка. Но фундаментальных ограничений нет, во многих случаях он уже работает.
Ага, а как на счет кэша скомпилированных функций? Перед каждым вызовом будьте добры сделать лукап, ну и апдейт кэша после компиляции, если вхождение не было найдено.
Не понял, зачем лукап перед каждым вызовом? Когда типы выводятся компилятором, этого точно не происходит; если типы невозможно вывести — ставится «лукап», либо из нескольких вариантов, либо если вообще ничего неизвестно — полноценный динамический.
Например, когда есть два варианта:
> f(a, b) = a * b
> h(a) = f(rand(Bool) ? 1 : 1.0, a)
> h(1) # возвращает либо 1::Int, либо 1.0::Float
> @benchmark h(1) # показывает, что h(1) занимает 5-8 ns
> @code_native debuginfo=:none h(1)
# под спойлером
pushq %r14
pushq %rbx
pushq %rax
movq %rsi, %rbx
movq %rdi, %r14
movabsq $rand, %rax
callq *%rax
movabsq $4607182418800017408, %rdx # imm = 0x3FF0000000000000
movl $1, %ecx
testb $1, %al
cmoveq %rdx, %rcx
jne L70
vcvtsi2sd %rbx, %xmm0, %xmm0
vmovq %rcx, %xmm1
vmulsd %xmm1, %xmm0, %xmm0
vmovsd %xmm0, (%r14)
movb $1, %dl
xorl %eax, %eax
jmp L81
L70:
imulq %rbx, %rcx
movq %rcx, (%r14)
movb $2, %dl
xorl %eax, %eax
L81:
addq $8, %rsp
popq %rbx
popq %r14
Более полезный пример:
# если дали nothing - вернуть ноль, иначе умножить на 2
> f(x) = 2*x
> f(::Nothing) = 0
# хотим суммировать f(x[1]) + f(x[2]) + ...
> g(x) = sum(f, x)
# массив int'ов:
> a = rand(Int, 1000)
> @benchmark g(a)
# 80-90 ns
# массив int'ов и nothing'ов вперемешку:
> a = [rand(Bool) ? rand(Int) : nothing for _ in 1:1000]
> @benchmark g(a)
# 200-220 ns
В общем, даже в этой ситуации, где типы принципиально нельзя вывести статически (и есть лукап во время выполнения), получился весьма эффективный код. Даже simd используется, судя по времени.
Этот подход эффективен — если Вам нужно запустить одну такую команду-программу. Но, опять же, есть аналогичная проблема — компилятор вынужден анализировать команды по одной, не видя общей картины. Например:
> f(x) = x
> g(x) = sum(f, x)
> a = [1 for _ in 1:1000]
> @benchmark g(a)
Если этот код компилируется по одной команде — будет цикл с суммированием. А если весь сразу — будет просто «return 1000».Так вот я утверждаю, что каждая такая программа перед запуском полностью компилируется (включая все то, что она вызывает). Согласны с таким образом сформулированной позицией?
По-моему это принципиально невозможно сделать. Например:
> g() = eval(Meta.parse(readline()))
# вызываем g(), набираем в консоли код - он исполняется
# или
> g(x) = some_function(deserialize(x))
# вызываем g("file_name"), из этого файла десериализуется объект, на нём вызывается some_function
# или даже так
> g() = eval(Meta.parse(randstring(Char.(30:128), 123)))
# вызывать g()
# обычно будет ошибка,
# но возможно иногда случайно получится валидный код
Во всех трёх случаях при вызове функции g() нельзя определить, какие ещё функции будут вызваны. Это можно сделать только потом, когда часть кода g() будет выполнена.
Если этот код компилируется по одной команде — будет цикл с суммированием. А если весь сразу — будет просто «return 1000».
А для какого языка компилятор сможет сделать "return 1000", если a
имеет ссылочный тип?
Если a
будет иммутабельного типа и помечена как константа, то всё свернётся (но это не точно). Например, с пакетом StaticArray, добавляющим иммутабельные массивы фиксированного размера:
julia> f(x) = x
julia> g(x) = sum(f, x)
julia> const a = @SVector [1 for _ in 1:1000]
julia> @code_native (function () g(a) end)()
.text
; ┌ @ REPL[8]:1 within `#10'
movl $1000, %eax # imm = 0x3E8
retq
nopw %cs:(%rax,%rax)
; └
(если смотреть код для g(a)
, то покажет код для g
только в предположении, что аргумент — статический массив, не подставляя конкретное содержимое, поэтому в последней команде вызов обёрнут в функцию).
Весь код показан — просто открываете REPL и вводите ровно то, что в моём комментарииЕщё раз. У вас не показан код который вызывает оверхед. И так понятно, что leaf-функции будут откомпилированы в нативный код. Смотреть на них не интересно.
Оверхед будет в программе, которая вызывает вашу функцию, если функция не проинлайнена.
При выполнении этого кода уже не важно, когда он появился — заранее или во время выполнения — скорость будет такая же. С чего вообще по-другому может быть?
Т.е. рантайм затраты на лукап и компиляцию функции вы не считаете оверхедом?
*facepalm*
Вызвать функцию в 5 строк из REPL и выполнять некий софт со 100 мегабайт кода это несколько разные вещи.
Да, возможно я не уточнил, т.к. считал очевидным — какой тип имеют литералы. 1 и 2 — типа Int64, поэтому f(1, 2) вызывает f(::Int, ::Int).
Языки такого плана обычно не умеют нормально работать с int.
Ваша функция с int не выполняет целочисленное деление.
Она переводит int в double, а потом делит даблы.
Например, предложенный в моём предыдущем комментарии вызов g(a, 2.0) у меня на лаптопе выполняется за ~70 ns.
Так же из repl дёрнули? Так он компильнулся / проинлайнился, оверхед вызова скрыт. Это не показывает ничего, кроме наличия jit — компилятора.
К тому же про 70нс я очень сильно сомневаюсь.
70 нс это латентность одного обращения к памяти.
Давайте посмотрим на инструкцию VDIVSD (на 4GHz Skylake)
:VDIVSD xmm, xmm, xmm L: 3.49ns= 14.0c T: 1.00ns= 4.00c
В цикле 100 итераций, но div не в цепочке зависимости, поэтому имеем время их исполнения не 14*100, а 4*100 тактов == 100 нс, если компилятор не векторизировал цикл (буду приятно удивлён, если векторизировал).
Ваша функция с int не выполняет целочисленное деление.Вроде бы у Julia такая семантика деления, целочисленное там другим значком.
Она переводит int в double, а потом делит даблы.
docs.julialang.org/en/v1/manual/mathematical-operations
Оверхед будет в программе, которая вызывает вашу функцию, если функция не проинлайнена.
Да никакого оверхеда не будет, откуда у вас это мнение? Не заинлайнена функция — будет её вызов, такой же как в условном Си. Попробуйте сами, если не верите — надо что-нибудь поверх моих функций из примера накрутить чтобы компилятор не вставлял их по месту.
Конечно, если типы нельзя вывести, будет их проверка во время выполнения и после компиляции (см. функцию h из примера) — но от этого никуда не деться, независимо от языка и «статичности» компиляции. И в большинстве случаев оверхед этой проверки в жулии весьма небольшой.
Т.е. рантайм затраты на лукап и компиляцию функции вы не считаете оверхедом?
Не знаю, где вы это прочитали. Про оверхед на компиляцию я явным образом писал, что он есть. «Лукап» функции после компиляции будет только если тип не вывелся — см. предыдущий абзац.
Языки такого плана обычно не умеют нормально работать с int.
Какого «такого» плана? Как «нормально»? Делить нацело можно, делить по-обычному тоже можно — просто это разные операторы.
Ваша функция с int не выполняет целочисленное деление.
Она переводит int в double, а потом делит даблы.
Конечно, если я в функции пишу "/" то я и ожидаю деление — без округления нацело, если вдруг в эту функцию передали инты. Нужно округлённое деление — так и пишите в коде, будет вам (стандартное хардверное) деление нацело.
Так же из repl дёрнули? Так он компильнулся / проинлайнился, оверхед вызова скрыт. Это не показывает ничего, кроме наличия jit — компилятора.
Поведение в repl и в коде из файлов в аспекте скорости и подхода к компиляции абсолютно никак не отличается.
К тому же про 70нс я очень сильно сомневаюсь.
70 нс это латентность одного обращения к памяти.
При бенчмаркинге функция запускается много раз, так что всё в кэше находится. Разумеется, никак нельзя достичь 70 нс если отсчитывать время от запуска программы до вывода результата на экран.
В цикле 100 итераций, но div не в цепочке зависимости, поэтому имеем время их исполнения не 14*100, а 4*100 тактов == 100 нс,
Вполне возможно, что я действительно куда-то не туда посмотрел в прошлый раз. Сейчас перепроверил — выходит 100-110 ns.
если компилятор не векторизировал цикл (буду приятно удивлён, если векторизировал).
Вроде бы, судя по командам, цикл не векторизирован. Для векторизации нужно перед словом for добавить simd — тогда время работы сокращается раза в 2 у меня.
Numpy — это не питон
Думаю что в будущем, когда остановится развитие ПО backend и desktop приложения будут писать на языках типа c++ и rust.
Не уверен. Оптимизации из статьи начиная с четвертой не очень то и зависят от языка программирования. Сборщик мусора тут тоже мимо — на весь тест три объекта.
Я бы поставил на языки с нормальный типизацией, которые будут давать возможность нормально задавать на уровне типов подобные оптимизации. Ну или для начала удобные библиотеки для работы со стандартными оптимизациями.
И по прежнему 80% будет уходить на ожидание, диска ли, сети ли… Но можно ждать быстрее!
Не уверен. Все приложения всё ещё используют БД и там как упирались в диск, та и упираемся. С latency пока не сильно хорошо.
Попытка использовать samsung 970 под бд привела к его смерти за 2 месяца. Сначала тоже казалось, что отличное решение и под ноут подходит. Сейчас у меня хорошего решения нет. Да и по цене я не назвал бы это массовым.
У меня 2 штуки SSD Samsung работают почти непрерывно 6 лет — один система, другой рабочие файлы. Так вот смарт показывает оставшийся ресурс 91 и 99% соответственно.
Странно, потому-что у меня с хардами прямо противоположная ситуация. Если использовать под систему и на нём-же проводить всякие сборочки: начинал дохнуть где-то через полгода-год. С ssd ситуация противоположная: 2 года, 500 гб обьём (CT500P1SSD8), используется в качестве системного диска и под проекты тоже (брался из-за хорошего показателя 4k random write). 24.6 терабайт записаных за этот период, полёт нормальный (drive remaining life рапортует 90%), нареканий ноль.
Странно, потому-что у меня с хардами прямо противоположная ситуация. Если использовать под систему и на нём-же проводить всякие сборочки: начинал дохнуть где-то через полгода-год. С ssd ситуация противоположная: 2 года, 500 гб обьём (CT500P1SSD8), используется в качестве системного диска и под проекты тоже (брался из-за хорошего показателя 4k random write). 24.6 терабайт записаных за этот период, полёт нормальный (drive remaining life рапортует 90%), нареканий ноль.
Ну а у меня за последние 10 лет сдохло 20% SSD и 5% HDD.
Понятно, что если брать локальное приложение, оно будет упираться в диск как в самый медленный элемент, но в вебе всё же по тормозам лидирует сеть.
Все приложения всё ещё используют БД и там как упирались в диск, та и упираемся
Что, прямо все-все приложения на свете? :)
В кровавом энтепрайзе работают не только лишь все.(с)
У меня вот ни одна задача не упирается в диск.
Когда проект в десятки мегабайт кода собирается на 16 ядрах, SSD загружен на 0-1%.
Просто обычно в варианте «у нас спутниковый канал а значит пинг в полсекунды и полоса узкая а нам надо работать».
Как в тупом варианте для обычных пользователей (которым http нужен(тогда еще https был редкий) — Globax/TelliNet (спецпрокся сразу запрашивает кроме страницы еще и картинки) так и серьезные оптимизации протоколов вроде SMB чтобы снизить количество запросов + кэшировать информацию локально и передавать дельты. Это например продукты от Riverbed делают.
В HTTP/2 есть попытки оптимизировать по минимуму (например — то что не надо каждый раз соединение устанавливать и гонять TCP и TLS рукопожатия)
В HTTP/2 есть попытки оптимизировать по минимуму (например — то что не надо каждый раз соединение устанавливать и гонять TCP и TLS рукопожатия)
Как ни странно, этого не приходится делать даже в HTTP/1.1, если использовать заголовок «Connection: keep-alive». Причём, это используется везде, даже в библиотеках вроде requests для Python и cURL для PHP.
Как в тупом варианте для обычных пользователей (которым http нужен(тогда еще https был редкий) — Globax/TelliNet (спецпрокся сразу запрашивает кроме страницы еще и картинки)
Я правильно понимаю, что это те системы, которые передают все данные всех пользователей через 1 спутниковый канал на землю, а исходящий траффик через другой канал?
И именно там была популярна «рыбалка», когда более подкованный пользователь перехватывал входящие спутниковые пакеты, адресованные не ему, и мог прочитать чужой http-траффик. (привет угон кукисов и прочие радости)
Робин Мартин предполагает, что хороший способ приступить к решению проблемы — разделить библиотеки. Вместо того, чтобы создавать одну большую библиотеку, которая делает всё возможное, просто создать много библиотек.
Таким образом, программист должен только выбрать библиотеки, которые ему действительно нужны, игнорируя функциональные возможности, которые он не собирается использовать. Мало того, что он сам устанавливает меньше зависимостей, но и в используемых библиотеках тоже будет меньше своих зависимостей.
Это как? Если вместо одной большой библиотеки будет много маленьких, каким образом я уменьшу количество зависимостей?
Разве это не тот путь, которым пошли с npm.js, и который в итоге приводит к 13000 зависимостей?
Это как? Если вместо одной большой библиотеки будет много маленьких, каким образом я уменьшу количество зависимостей?
Большая библиотека А может иметь компоненты b, c, d с зависимостями E,F,G соответственно. То есть библиотека A зависит от библиотек E, F, G. Разделяя библиотеку на библиотеки Ab, Ac, Ad (с зависимостями E,F,G соответственно), мы даём возможность пользователю подключить только библиотеку Ab c зависимостью E (если ему не нужны компоненты c, d), и не тянуть зависимости F, G ненужных компонентов.
Это приводит к множеству мелких зависимостей, которые можно подключать, скажем так, меньшими порциями.
Это связано со сложностью ПО. Если есть 13000 различных функций (или связанных групп функций), число библиотек будет такого же порядка.
число библиотек будет такого же порядка
Как по мне, это проблема. В общем случае, я бы предпочел одну большую библиотеку + tree shaking, чем 10 маленьких:
- больше вероятность, что она написана в одном стиле;
- не возникнет конфликтов между версиями, когда библиотека A требует библиотеку C v1, а библиотека B требует библиотеку C v2;
- меньше вероятность дублирования кода, поскольку компоненты одной библиотеки знают о существовании друг друга;
- проще обновить одну библиотеку на новую версию, чем 10;
- компоненты одной библиотеки будут совместимы между собой;
- и т.д.
Согласен, но, на мой взгляд, проблема библиотек не только и не столько в том, что в них содержится "лишний" код (кстати, tree shaking всё-равно не сможет удалить абсолютно весь лишний код), сколько в том, что несколько последних поколений разработчиков обучены иначе думать — они ищут и подключают библиотеки на каждый чих, даже там, где можно было решить проблему написав десяток строк кода ручками.
Это распространённое заблуждение:
- Этот десяток строк нужно протестировать ровно так же, как и любой другой десяток строк нашего кода — никакой особой разницы тут нет.
- Насколько протестирован аналог этих строк в библиотеке — обычно никто не знает, и при выборе библиотеки на это не смотрит.
- Поиск подходящих библиотек и выбор из нескольких альтернатив занимает время, нередко превышающее время на написание и тестирование этих 10 строк.
- Добавление дополнительной зависимости в проект создаёт дополнительные риски и увеличивает стоимость поддержки проекта само по себе (которые принято игнорировать, но если прятаться под одеялом то монстр всё-равно никуда не исчезнет) — лицензии, зависимость от стороннего вендора, куча лишнего кода с потенциальными уязвимостями и т.д. (подробнее в https://habr.com/ru/post/443620/). Но если их не игнорировать, то стоимость поддержки и тестирования своих 10 строк почти всегда окажется значительно ниже стоимости поддержки дополнительной зависимости.
Я веду к тому, что добавление зависимости — не должно быть первым/основным/механическим ответом на любую проблему, потому что у него вовсе не нулевая стоимость, как принято думать.
Не, то что вы описали, это про "в используемых библиотеках тоже будет меньше своих зависимостей" – тут я не спорю. Транзитивных зависимостей может быть меньше. Прямых зависимостей никак не может стать меньше.
Прямые зависимости — они явные. Транзитивные зависимости — неявны, этим они и страшны.
И? Какое отношение это имеет к моему изначальному вопросу?
Транзитивные зависимости вызывают большее беспокойство, чем прямые (прямые подключаются явно, а не ВНЕЗАПНО, они все видны). Описанный способ борется с лишними транзитивными зависимостями.
Описанный способ приведет (и приводит) к аду с управлением зависимостями, когда библиотека A зависит от библиотеки C v1, а библиотека B зависит от библиотеки C v2. А я про эту библиотеку C вообще ничего не знаю, и она мне нафиг не сдалась бы. И чем больше таких микро-библиотек, тем больше вероятность конфликтов.
Но это все лирика, повторюсь, к моему изначальному вопросу это не имеет никакого отношения.
к моему изначальному вопросу это не имеет никакого отношения.
По-моему, я описал механизм, как эта идея работает. Это отвечает на вопрос "как?"
Ну я же не зря в цитате выделил жирным шрифтом места. Из выделенных фрагментов получается, что если разбить одну большую библиотеку на много маленьких, то прямых зависимостей станет меньше.
Я утверждаю, что это невозможно даже в теории. А на практике даже общее количество прямых и транзитивных зависимостей увеличивается, а не уменьшается.
А вы мне в этой ветке говорите про то, что транзитивные зависимости вызывают большее беспокойство. Отсюда и вопрос: "И что?"
В случае с примером, описанным Akon32, библиотека A разбитая на библиотеки Ab, Ac и Ad — это одна библиотека. Все зависимости в данном случае должны быть едиными и иметь общую версию. Кроме того, версия библиотек Ab, Ac и Ad тоже должна быть общей, даже при выпуске новой версии где изменения коснулись только одной части. Если придерживаться этих правил проблем с зависимостями точно не прибавится.
При этом транзитивных зависимостей будет меньше только в теории. На практике же, если библиотека A тоже пошла этим путем, то Ab будет зависеть не от E, а от Ex, Ey, Ez. Каждая из которых, в свою очередь, будет зависеть еще от 5 микро-библиотек.
Получается, что вместо зависимости A –> E, F, G, у меня будет Ab, Ac –> Ex, Ey, Ez, Fp, Fq -> *
На практике же, если библиотека A тоже пошла этим путем, то Ab будет зависеть не от E, а от Ex, Ey, Ez.
Если E пошла тем же путём, возможно, что в зависимости Ab можно прописать только Ex, а не все Ex, Ey, Ez, поэтому ни Ey и Ez, ни их зависимости грузиться не будут; и т.д.
На практике может быть и так, что нужны все Ex, Ey, Ez, и тогда преимущества такого способа нет.
Теоретически да, практически — далеко не всегда.
- Во-первых, поскольку нет единообразия, и учитывая, что для решения одной задачи уже существуют как правило несколько альтернатив на выбор, многие транзитивные модули будут зависеть от разных библиотек, предоставляющих один и тот же функционал.
- Во вторых, транзитивные зависимости могут тащить разные версии одной библиотеки, и привести все это к общему знаменателю — серьезная проблема. Например производители дистрибутивов Linux или метафреймворков типа Spring Boot как раз решают эту проблему, унифицируя в каждой версии платформы большинство зависимостей.
С другой стороны проблемы не в размере самих библиотек, а в том, что современные технологии неприспособлены для автоматического dead code elimination. В сях все было просто: неважно сколько библиотек ты подключил — линкер урежет все, что статически недосягаемо из main(), делая очень компактный бандл. В других языках как Java, Python, JS пришлось искусственно городить модульную систему и требовать от пользователя каждый раз въявную указывать компоненты, которые он будет использовать. Так что это по большей части шаг назад.
В сях все было просто: неважно сколько библиотек ты подключил — линкер урежет все, что статически недосягаемо из main(), делая очень компактный бандл. В других языках как Java, Python, JS пришлось искусственно городить модульную систему и требовать от пользователя каждый раз въявную указывать компоненты, которые он будет использовать. Так что это по большей части шаг назад.
Угу, угу. И каково там управлять зависимостями на C? И что делать, если у двух зависимостей общая транзитивная зависимость, но разных версий?
- Во-первых, стек библиотек, поставляемый с платформой (версией ОС, SDK, etc), как правило всегда унифицирован транзитивно.
- Во-вторых, есть требование, чтобы библиотеки с одной и той же major version были обратно совместимы. http://www.sourceware.org/autobook/autobook/autobook_61.html В этом случае можно просто слинковать более свежую библиотеку.
- И в-третьих, в одном бандле можно использовать транзитивные библиотеки разных версий. Для этого линкер должен включить номер версии в таблицу символов.
https://blog.habets.se/2012/05/Shared-libraries-diamond-problem.html
- Во-первых, стек библиотек, поставляемый с платформой (версией ОС, SDK, etc), как правило всегда унифицирован транзитивно.
Но не все зависимости в этот стек входят.
- Во-вторых, есть требование, чтобы библиотеки с одной и той же major version были обратно совместимы. http://www.sourceware.org/autobook/autobook/autobook_61.html В этом случае можно просто слинковать более свежую библиотеку.
Или нельзя, потому что автор одной из библиотек завязался на багофичу определённой версии транзитивной зависимости и апгрейд зависимости сломает библиотеку. Или просто в новой версии транзитивной зависимости добавили новую функцию, которая имеет то же имя, что и в библиотеке.
- И в-третьих, в одном бандле можно использовать транзитивные библиотеки разных версий. Для этого линкер должен включить номер версии в таблицу символов.
https://blog.habets.se/2012/05/Shared-libraries-diamond-problem.html
Окей, это интересно (нет, серьёзно), но что делать с зависимостями, которые линкуются статически? И да, в других языках это просто работает, без дополнительных телодвижений со стороны программиста.
это просто работает
Просто это работать не может. Если есть цепочка A-B-D1 и А-С-D2 и нужно объект из библиотеки D передавать между функциями из B и С. Как это сделать?
Если же библиотеки D1 и D2 не торчат наружу, то возможно конкретная реализация в Си немного тупая. Но в целом решение очевидное.
Просто это работать не может. Если есть цепочка A-B-D1 и А-С-D2 и нужно объект из библиотеки D передавать между функциями из B и С. Как это сделать?
Если вы не указали, чтобы B и C использовали одну и ту же версию — никак, у вас объект из библиотеки D разных версий, т. е. фактически разных библиотек.
Окей, это интересно (нет, серьёзно), но что делать с зависимостями, которые линкуются статически?
Я не разрабатываю на Си, но насколько я могу судить (да поправят меня знающие люди), нет большой разницы слинкована библиотека динамически или статически. Любое приложение можно слинковать обоими способами (чем пользуются всякие flatpack и snappy). В первом случае резольвинг идет в рантайме на этапе загрузки бандла, тогда как во втором — сразу на этапе линковки бандла. Правила резольвинга не должны отличаться.
Или просто в новой версии транзитивной зависимости добавили новую функцию, которая имеет то же имя, что и в библиотеке.
Когда говорят о транзитивных зависимостях, почему-то нигде не указывают тип транзитивности. Вне зависимости от языка программирования любая библиотека всегда состоит из двух частей: интерфейса (структуры, типы, сигнатуры функций) и имплементации (непосредственно код). Интерфейс библиотека экспортирует наружу, тогда как имплепентация — это внутреннее поведение библиотеки. Если транзитивная зависимость используется полностью в имплементативной части библиотеки, то нет никаких проблем иметь разные версии в разных зависимостях: различные платформы предоставляют свои средства "изоляции" (namespaces, dynamic linkers, classloaders, etc...).
Если же библиотека экспортирует в своем интерфейсе элементы из транзитивной зависимости, то тут нет простого решения, т.к. описания из транзитивных интерфейсов разных версий могут конфликтовать в одном бандле. Выделяют частный случай, когда описания обратно совместимы, например, когда в интерфейс добавили новые элементы, не модифицируя старые. Для этого при компиляции берут интерфейс более свежей библиотеки, а на этапе линковки можно слинковать те транзитивные версии, которые требуются каждой из библиотек (если платформа позволяет их корректно изолировать).
Если же транзитивные интерфейсы несовместимы, то все плохо: одну из веток зависимостей придется полностью изолировать или даже виртуализировать и писать к ней адаптер (ну или как вариант оставить все как есть и посмотреть что будет).
Если транзитивная зависимость используется полностью в имплементативной части библиотеки, то нет никаких проблем иметь разные версии в разных зависимостях: различные платформы предоставляют свои средства "изоляции" (namespaces, dynamic linkers, classloaders, etc...).
Только не в C, там из средств изоляции только static для функций.
Тут таки сложнее. В Windows, например, статические библиотеки линкуются как внутрь основного бинарника, так и внутрь DLL (это долго относилось, а может, и сейчас, к CRT — C runtime library); если статическая библиотека это не импорт DLL, то каждая DLL получит свою копию этой статической, со своей версией и своими глобальными переменными. Поэтому лучше, например, malloc/free/new/delete делать переходниками на соответствующие функции user32, если нет жёстких причин делать иначе; если же рантаймы у двух DLL различаются, то возникает жёсткое правило что освобождать память должна та же DLL, что её аллоцировала.
В Unix, соответствующие уровни обычно сделаны в общей libc, а в общем случае подключается только одна библиотека (самая свежая) каждого типа, но и там можно при желании натворить хаков — статическая линковка внутрь SO, прямой dlopen на желаемую библиотеку, и прочая и прочая.
> Вне зависимости от языка программирования любая библиотека всегда состоит из двух частей: интерфейса (структуры, типы, сигнатуры функций) и имплементации (непосредственно код). Интерфейс библиотека экспортирует наружу, тогда как имплепентация — это внутреннее поведение библиотеки.
Теоретически — да. Практически же этот механизм приводит к тому, что ссылка двух DLL друг на друга по кольцу без явного резолвинга в коде уже ломает всё, и аналогично для .a (.lib).
Деление на интерфейс и реализацию в этой схеме совершенно нетипично, это не классовая иерархия.
"Нужно оптимизировать ПО" — весьма банальная идея.
Программы, в которых действительно нужна скорость, и так тщательно оптимизируются.
Но есть и такие программы (и их много), где не важно, 100 или 200 миллисекунд будет обрабатываться нажатие кнопки. А процесс оптимизации — это некоторые затраты.
Робин Мартин предполагает, что хороший способ приступить к решению проблемы — разделить библиотеки. Вместо того, чтобы создавать одну большую библиотеку, которая делает всё возможное, просто создать много библиотек.
В ряде случаев это, конечно, хорошая идея, но постоянная память сегодня практически ничего не стоит. Какая-нибудь SD карта размером с ноготь может хранить сотни гигабайт. Нет смысла беспокоиться, пока система не начнёт работать настолько плохо, что за неё станет стыдно (или пока конкуренты не прижмут). Если 100500МБ библиотек перестали влезать в SSD — определённо, надо что-то делать.
Ну и собственно разделение библиотек может быть хорошей идеей по ряду других причин, не связанных с объёмом исполняемого кода, например уменьшение вероятности некоторых конфликтов зависимостей.
Если предложить разработчику поработать на старом нетбуке с процессором Atom и двумя гигами оперативки и подключить его через ADSL, то наверняка он сразу задумается об оптимизации своего софта. И не только своего.
Проблемы пользователей разработчиков не волнуют. По крайней мере проблемы 10-20% пользователей с наиболее слабым железом. Они кассу не делают.
Благо, ютуб пока что ещё смотрится через mpv, а в гугломейле не отрезали классический HTML-вид, но это пока :-)
пользователи уходят к другим поставщикам софта
… с новым глюкодромом и тормозами. А от «другого» поставщика переходит кто-то к первому, лелея мрию что тут ему сделают красиво :)
Повторюсь: оптимизация начнется, когда стоимость разработки станет меньше стоимости железа.
По моему опыту, оптимизация начинается лишь тогда, когда пользоваться неоптимизированным ПО невозможно. Вопрос денег поднимается только потом.
Оптимизировать или нет — в первую очередь вопрос необходимости, а уже только потом — вопрос денег. Иногда даже бывает, что необходимость определяется не отзывами пользователей, а другими причинами типа конкуренции.
(это в основном про коммерческую разработку, а не про кодинг для души)
В современном мире оптимизацией, как правило, начинают заниматься только тогда, когда этого уже ну никак нельзя избежать. Когда производительность оказывается абсолютно неприемлемой.
Это доведенный до крайности принцип «решать проблемы по мере их поступления».
А можно ликбез зачем линкеру столько памяти? Казалось бы ему надо примерно столько, сколько будет весить итоговый бинарник. Развен он строит какое то дерево зависимостей по ходу дела?
не у линкера не хватало памяти, а у самого получающегося бинаря — ОС не могла его загрузить, потому что слишком много туда было влинковано, и оно тоже выходило за какие-то пределы
Банальный виндовый exe (PE) не может быть больше 2ГБ. Лимиты ближе, чем кажутся. Я видел dll от nvidia размером в несколько сотен МБ.
То есть это вопрос не того, что непонятно чего накодировали, а использования DLL в качестве «коробочки» для хранения картинок и чего-то там ещё.
Извините, ваша теория разбивается об энергопотребление современного железа.
Людям нужно чтобы ноутбук держал 5-10 часов. У нас есть работающая, но тормозящая программа. Пользователи пользуются. Но как только конкурент сможет предоставить более энергоэффективный аналог, это станет решающим фактором для части пользователей.
На десктопе отличие в том что сейчас счет пошел на сотни ватт. Пользователи не будут ставить чиллер чтобы пользоваться ПО про которое пишите вы.
Могу привести пример — Скайп. Когда-то безальтернативное решение, и один из сейчас. Последние несколько лет в связи с деградацией производительности точно потерял часть рынка.
А как вы решите деньгами разряжающийся за 2 часа ноутбук на core i7 8 поколения?
можете показать выписку с донатами Mozilla (если Вы ей пользуетесь), Canonical (если пользуетесь Ubuntu), Eclipse Foundation (если пользуетесь Eclipse IDE)?
Давайте без выписки. Если вам интересно, поддерживал и поддерживаю свободное ПО как Ubuntu, phpmyadmin и прочие линуксы. Буквально несколько дней назад отправил 10$ Википедии.
Вы правы, я буду платить за быстрое ПО.
Скайп — опровержение вашей теории о "решающем факторе". Да, он теряет пользователей из-за тормознутости и глючности. Но вы сами можете видеть, что теряет он их недостаточно быстро. То есть на практике этот фактор влияет не особо сильно (хорошо хоть влияет). Любой тормознутый софт может годами использоваться десятками миллионов пользователей.
Даже у более успешных конкурентов или чего-то нет или что-то неполноценное неудобное или что-то, что в Скайпе второй десяток лет, завозят вот только что.
Огромное количество софта такое — им пользуешься потому, что пользуются другие. Например, комментирование хабра на мобильных сделано отвратительно — необходимо прогрузить и отрисовать все, что бы ответить на один. Самые популярные посты комментировать вообще нельзя — оно просто не отрисуется.
Так же что Скайп, к сожалению, хороший пример. Пока 80% готовы мириться с плохой скоростью ПО, остальные 20% тоже будут. Скорость — не определяющий фактор.
офисный пакет
Если файлы сложные — не можете. У ваших клиентов просто поедет всё, придётся вам потерпеть. Если файлы простые, то повезло.
браузер
Не можете. Движка осталось, фактически два, более одного раза не поменяете. Скины к хрому не в счёт, их вы правда можете менять.
Скайпом перестали пользоваться не из-за деградации производительности, а из-за деградации качества самого приложения — глюки, реклама, убогий UX, И так далее.
А если, к примеру, я предложу Discord с показателем потребления /10, но за подписку 5$/месяц?На самом деле, цены на freemium-софт сильно завышены, потому что каждый покупатель подписки платит за себя и
Так вот если заставить платить всех без исключения, то 5 баксов в месяц могут легко и непринужденно превратиться в 5 баксов в год :)
Заставить? Какая классная идея, модная, современная.
Меня ещё ни разу не заставляли платить за колбасу. Хочу покупаю, хочу нет. Те же и с сервисом. Хочет человек — делает платный сервис, хочет — с премиум-подпиской. Но если он сделает платный, клиенты могут уйти на условно бесплатный, если захотят. Никакое "заставить платить" тут быть не может.
Никакое «заставить платить» тут быть не может.
Винда же (если без пиратства). Да, есть линуксы, но сидя на работе под линуксом, дома поставил винду, потому что даже в steam из всех игр что у меня куплены — в линь умеют процентов 10 от силы. Плюс под винду написана просто масса по, которого нет под линь, а аналоги… Вот чем заменить мс офис именно при серьёзном документообороте? openoffice, libreoffice — простые документы обычно норм, но сложные, со сложным форматированием, с режимом комментирования — ломаются в 90+% случаев. То нумерация уплывает, то страницы рвутся криво, то вёрстка уезжает и иногда это важно… Мы пытались использовать и линухи и *офисы, но по моему субъективному опыту — самым стабильным был ooo 2.2 (выпущенное году этак 2010, последний раз сравнивали году в 2015), а либра била доки даже те, которые в ооо 2.2 показывались как надо.
И это при том что режим правок например терялся полностью. Итог — внутри фирмы — ООо, всем кто общался с клиентами и вообще с миром — винда и мс офис.
Возможно, мак был бы решением, там вроде как есть и мс офис и ещё много софта, но он сам по себе дороже и это отдельная экосистема.
простые документы обычно норм, но сложные, со сложным форматированием, с режимом комментированияВот никогда не понимал, а зачем нужны «сложные» доковские документы. Либра рецензирование, формулы и ссылки вполне себе вывозит в 5 версии.
Вот никогда не понимал, а зачем нужны «сложные» доковские документы. Либра рецензирование, формулы и ссылки вполне себе вывозит в 5 версии.
Внутри себя вывозит.
При импорте-экспорте — съезжает форматирование.
У кого как :)
Не у кого, а у чего.
Зависит от самого документа.
Причем съезжает форматирование и у элементарных вещей типа «выставить счет в OpenOffice и открыть в Excel или наоборот».
А счет это такая простейшая форма:

Вы можете предположить, что съезжает картинка с печатью или подписью?
Нет, съезжают рамки и то что в рамках написано.
Сталкиваюсь довольно часто.
это скорее всего связано с тем, что по-разному в ОО и Офисе ставится якорь картинки
Написано же — дело не картинке.
Нет, написано, что съёзжает не картинка. Якорь может сбивать позиционирование полей и границ других элементов. Я с этим сталкивался, когда документ из 2007 перекосило в 2003, долго рассуждал о неочевидности решения инвективной лексикой.
Видимо напрасно пример был с картинкой, ввел вас в заблуждение.
Ну ОК. Ровно такой файл, состоящий из надписей и рамок имеет нередко ровно такие же проблемы.
Без картинок.
Берём сложнее. ТЗ. То есть документ, с которым работают обе стороны. И тут история правок и «совместная работа» это жизненно важно. Да, сейчас берём тот же гугл докс и не знаем бед, но суть была именно в локальном редакторе.
Ну и всякие рамки ползут даже в простых доках, это да.
Разница в производительности играла бы какую-нибудь роль, если бы была видна. Но почему-то в списках/обзорах программ для задачи X из потребления ресурсов в лучшем случае указывают размер apk.
Хотел бы я, чтобы обзоров с измерениями было больше.
Разработчики даже в рамках госрегулирования чисто своей отрасли ничего лоббировать не осилят (каждый в своей кастрюльке варится, пока зарплаты относительно высокие), а вы про изменение культуры потребления ПО в принципе.
Вот по крайней мере для России.
Есть госреестр отечественного по.
И если будут включены требования по скорости, хотя бы по скорости отклика и по памяти.
Разработчики вынуждены будут изменить по, для включения в данный реестр.
И если будут включены требования по скорости, хотя бы по скорости отклика и по памяти.
Разработчики вынуждены будут изменить по, для включения в данный реестр.
Какая "интересная" идея. Ресурсоёмкое ПО сразу вылетает из реестра. Остальные пишут костыли, чтобы удовлетворить формальным требованиям.
А когда железо подешевеет, ПО его не может использовать, потому что законодательно будет ограничено лимитом, аналогичным "640кБ". Развитие приостановится.
Имхо, вместо этого лучше пролоббировать "разработчики обязаны ходить строем". Это сократит время на перемещения и просто красиво (по мнению некоторых).
Отчасти эту проблему можно разрешить изменением культурыИли, другими словами — невозможно.
Тут есть много факторов, скорость удобство цена, но потребление батареи у меня один из ключевых. Особенно на телефоне, где каждый калькулятор норовит висеть в бэкграунде и сливать телеметрию все сутки на пролет. Зоопарк мессенджеров это вообще идиотизм. Скайп на компе включаю только если надо позвонить по видео и потом сразу выключаю.
Да блин я бы хоть сейчас задонатил бы на хабр если бы они наконец убрали поыиксиили тормознутые комментарии, и сделали бы полноценную мобильную версию.
Скайп на компе включаю только если надо позвонить по видео и потом сразу выключаю.
У вас какая-то эгоистично-односторонняя связь получается. А если кому-то другому надо позвонить вам с видео — что делать? Связываться с вами по другому каналу связи и нижайше просить вас включить скайп?
Ну и второй вопрос — если для вас решающим фактором является энергопотребление — зачем выключать скайп на десктопе?
Тоже так думаю. Идеальный пример Whatsapp и и Telegram. Первый вышел на рынке раньше и сейчас является монополистом практически, на фоне телеграмма, который уделывает его по всем параметрам, но большинство, как пользовалось whatapp, так и пользуется. Кроме тех людей, которые попробовали telegram конечно...
Вацап — это вполне себе интернет-телефон и видеофон с самого начала.
Вацап — это вполне себе интернет-телефон и видеофон с самого начала.
Это не так. Изначально WhatsApp был заменой SMS и ничего кроме сообщений не умел. И причём был платным.
Первый выпуск приложения относится к январю 2009 года. К апрелю 2012 года ежедневно при помощи WhatsApp пересылалось 2 миллиарда сообщений, более 10 миллиардов в августе 2012 года, более 27 млрд в июне 2013 и более 50 млрд сообщений на март 2015. В феврале 2018 около 1 млрд человек отправляли через WhatsApp 55 млрд сообщений в день.
По мнению, опубликованному в газете Financial Times, приложение WhatsApp сделало с SMS то же, что сделала программа Skype с международными телефонными звонками.
В феврале 2014 года CEO WhatsApp намекнул, что к лету планируется добавить функциональность VoIP-звонков между пользователями, и в конце марта 2015 года эта функция была реализована на платформе Android. В апреле 2015 года звонки появились на платформе iOS. В июне 2015 года функция стала доступна владельцам Windows Phone.
19 февраля 2014 года компания Facebook Inc. объявила о приобретении WhatsApp за 19 млрд долларов.
WhatsApp стал бесплатным с 18 января 2016 года. Ранее за подписку на использование сервиса взималась плата в размере около 1 доллара США каждый год, начиная со второго года использования, либо (для платформ Apple), однократный платёж при покупке приложения
К 2015 году WhatsApp стал самым популярным приложением для обмена сообщениями в мире, и по состоянию на февраль 2020 года в нем насчитывалось более 2 миллиардов пользователей. WhatsApp стал основным средством электронной связи во многих странах и регионах, включая Латинскую Америку, Индийский субконтинент и большую часть Европы и Африки.
Пользовался и телеграмом и вотсапом на смартфоне, не вижу, чем именно телеграм лучше.
Повторюсь: оптимизация начнется, когда стоимость разработки станет меньше стоимости железа.
Наверное даже так: оптимизация начнется, когда стоимость разработки и поддержки станет меньше дополнительной стоимости/задержек которые пользователи готовы заплатить за более оптимальный продукт, с учетом конкурентных продуктов.
Проблемы пользователей разработчиков не волнуют. По крайней мере проблемы 10-20% пользователей с наиболее слабым железом. Они кассу не делают.
Волнуют. В указанных в ТЗ рамках.
А если там например указано (или НЕ указано но сказано неявно) что телефоны с дисплеем меньше N" не поддерживаем — пользователю с таким — не повезло. Если по ТЗ надо при старте приложения показать пользователю продукты которые ну очень будут ему полезны — это и будет сделано.
Если надо сделать приложение «красивее» (пусть даже это значит на определенный период в приложении будет и новый и старый код ) — ну вы поняли.
Если надо «по соображениям безопасности» дергать 3rd party либу которая не только собирает данные все какие может но еще и спамит в logcat при этом (серьезно тормозя при этом работу) — ну значит максимум разработчики сделают возможность собирать версию где эта либа просто не инициализируется. Для себя сделают потому что в прод это выкатывать — «это ж безопасность».
Кэширование? Ну может быть сделаем, но нам же актуальность данных важнее.
И да, у меня есть старый нетбук с 2 гигами ОЗУ, которого мне долго хватало для разработки, но вот просмотр сайтов он уже давно не тянул, хотя как бы НЕТбук. Последнее время стало получше — Firefox-у всё-таки навели рефакторинг, но всё-таки.
Проблема в том, что у разработчиков ПО обычно топовые компьютеры с кучей памяти, быстрыми многоядерными процессорами и быстрыми дисками. И быстрый интернет.
Проблема в отсутствии тестирования в реальных условиях, а не в хорошем железе. Разработчику, кроме программы, ещё и инструменты разработки запускать надо. Хорошие инструменты довольно требовательны к ресурсам.
Беда в том, что программы так разжирели, что компилятор не может вычислить все возможные состояния программы.Соответственно тянет всё, что указано в коде.
Нет, это связано с чем-то другим, например, с динамической типизацией, динамической линковкой, может быть чем-то ещё. Например, java обычно тянет в jar все class-файлы, даже если не все они используются, — из-за динамической линковки. Можно подгрузить класс по имени. Delphi и С++ имеют статическую линковку, но, насколько мне известно, первый вырезает неиспользуемые функции из кода даже в огромных проектах, а второй — почему-то не очень.
Нет, это связано с чем-то другим
//ни один другой объектный файл не увидит эту функцию
static int func() {
// и этот массив тоже
// собственно он будет вырезан компилятором, если не вызвать эту процедуру
const static char arr[30 * 1024 * 1024] = { 50 };
int retval = 0;
// используем только пять первых байт, вероятность доступа к остальным 0%
for (int i = 0; i < 5; i++)
retval += arr[i];
// очевидно, что процедура вернёт 250
return retval;
}
int main()
{
printf("%d\n", func());
}
Основные точки возникновения нигде не вызваемых озёр кода — это именно стык разных систем от разных команд.
Тренд на параллелизацию виден уже сейчас.
Насколько я помню есть еще закон, говорящий что распараллелить эффективно можно только определённое количество раз. Дальше идёт довольно быстрое снижение эффективности, если дело касается одной задачи.
Общая информация понятна, но как это всё скажется на всём остальном? Сколько вариантов железа придётся делать под каждую задачу и почём все это железо потом будет стоить? Сейчас конечно мир пошатнулся, там ARM процессоры вышли вперёд, все сразу «захотели на них пересесть» потому что в отличии от «классического декстопного варианта» процессор не пересобирает лишний раз информацию и архитектура достаточно проста, но как оно пойдёт на пользовательском рынке — другой вопрос.
Мы же не зря пришли к мультизадачности, ко всему этому «мусору». Т.е. индустрия могла идти на поводу своих амбиций и где-то допускать ошибки и не туда сворачивать, но обычно всё возвращается на круги своя. Возникла потребность к приходу свежей крови, которая не сечёт конечно как работает логика процессора, не является программистами ядра, однако умеют довольно неплохо справляться с задачами, которые помогает от части решать более объемный язык.
То что пуля полетит быстрее ракеты на начальных этапах это конечно важно, но чтобы ударить ракетой по другой стране нужно как и соблюдать полётный план, так и предоставить средства защиты от ПВО, а казалось бы обычная банка с керосином и взрывоопасным веществом на борту.
Сложные системы становятся хаотичными, сколько в них всё не переставляй. А разделённым системам нужно пространство и свои инструменты под нужды каждого отдельного этапа. Может быть, какие-нибудь «жидкие процессоры» и смогут в будущем уместить в себя все нужные инструменты, но этого когда-нибудь, а сейчас если нужно — оптимизируй, но трать больше средств на поиск решений, пока твои конкуренты мчат на поезде из палок и гуано, покрашенным в красный цвет, а потом они его на ходу переделывают, добавляют еще палок, еще немного свеженького гуано, потом выпускают версию 10.1 в которой вроде все проблемы решены и это стало больше походить на поезд но из-за ошибок совершенных ранее некоторые палки стали упираться в новенькие колёса и так далее и тому подобное.
Частные случаи, они всегда такие лёгкие и невесомые. Такие решаемые, а потом ты на них всё-равно лепишь поверх всякое «нужное», а потом перебираешь, пересобираешь, ищешь маленькую трещинку, через которую льются все внутренности.
Насколько я помню есть еще закон, говорящий что распараллелить эффективно можно только определённое количество раз. Дальше идёт довольно быстрое снижение эффективности, если дело касается одной задачи.
Вы наверное говорите про закон Амдала? Но он про другое.
«В случае, когда задача разделяется на несколько частей, суммарное время её выполнения на параллельной системе не может быть меньше времени выполнения самого медленного фрагмента»
Эффективное количество параллельных потоков не может превышать количество независимых частей, на которые можно разбить задачу.
Если нужно четыре раза перемножить четыре разных числа, в четыре потока это будет(в идеальном случае) в четыре раза быстрее, чем в одном. Но увеличение числа потоков до восьми уже абсолютно бессмысленно. А ведь распараллелить можно только независимые задачи — если одна задача зависит от другой, как часто бывает, их в любом случае придётся выполнять последовательно.
Но увеличение числа потоков до восьми уже абсолютно бессмысленно.
Зато вы можете выполнять любую другую операцию на оставшихся 4-х ядрах.
Тут естественный лимит по нехватке данных.
Можно разбить задачи на более мелкие.
А ведь распараллелить можно только независимые задачи
Мой коммент был как раз про это.
Вот, например, скалярное произведение вектора.
dot = a.x*b.x+a.y*b.y+a.z*b.z
a.x*b.x, a.y*b.y, a.z*b.z < — параллельная часть
x' + y' + z' < — последовательная часть
Я это писал к тому, что распараллеливание это очень полезно, но не панацея — в зависимости от задачи вы сможете использовать от одного потока(например, вычисляя последовательность Фибоначчи) до N потоков(обрабатывая N атомарных задач) но увеличение до N*2 вам всё равно не поможет во втором случае, а в первом — вообще все дополнительные ядра будут простаивать.
в зависимости от задачи вы сможете использовать от одного потока(например, вычисляя последовательность Фибоначчи),… вообще все дополнительные ядра будут простаивать
Даже в такой простой по формулировке задаче есть куда параллелить. Если нужно число Фибоначчи с большим номером, то понадобится длинная арифметика — в умножении таких чисел есть что распараллеливать. Даже если без длинной арифметики, возведение матрицы в большую степень (а числа фибоначчи эффективно вычисляются именно так) можно считать в несколько потоков.
И это типичная ситуация: для многих задач есть многопоточные алгоритмы, которые работают быстрее однопоточных — даже если исходный алгоритм вроде как невозможно распараллелить из-за зависимостей.
Ну, оптимизировать-то всё равно надо не всю программу, а только узкие места (см. закон Парето). Так что "на коне" будут те, кто умеет пользоваться профайлером и мозгами для их поиска и устранения.
Быть может, это подходит для высокопроизводительных вычислений, числодробилок итп. Ну, или для крайних случаев, когда Windows читает файлы десятки тысяч раз при нажатии ПКМ. Но что делать, если софт "подлагивает" немного, но в куче мест? Вот, какое-нибудь модное приложение, а оно написано на React + Electron. Сначала запускается отдельный инстанс Chrome, потом немного парсится JS, JIT и все такое. Пользователь нажал кнопочку — создался какой-то объект (аллокация памяти), потом он прошел через десяток всяких редьюсеров, строки сравниваюстя, объекты создаются, пересоздаются, аллоцируются, удаляются, сборщик мусора пыхтит… Вроде, каждое отдельное действие быстрое и оптимизированное (напр., сравние строк внутри сишных библиотек на SSE), но все вместе приводит к тому, что итоговый результат чуть-чуть лагает. И из тысяч таких кусочков складывается картина, что железо становится мощнее, а обычный "юзерский" софт, в тех моментах, которые не упираются в числодробилки, все лагает и лагает. Быть может, я заблуждаюсь, но мне кажется, что тут профилированием не решить.
Вот, какое-нибудь модное приложение, а оно написано на React + Electron.
Может быть, просто не надо лепить такие поделия? Когда мессенджер жрет гигабайт оперативной памяти — это не серьезно.
Skype сейчас — это именно такое приложение. Там даже интерфейс сейчас лагает.
Я вам больше скажу — VS Code тоже сделана на электроне, и… не тормозит и не лагает.
После того, как там переписали ядро на C++ — да, не лагает. До этого лагала.
Какое ядро, вы о чем вообще?
А секунда на запуск это из кеша ОС, попробуйте после перезагрузки, желательно достаточно быстро, а то ОС по типу Windows сама всё в кеш утащит.
Так а с точки зрения пользовательского опыта разница какая — закеширует ОС или просто быстро приложение откроется?
Нода v12 на обычном среднем десктопе показала 1145 секунд.
Ну что тут сказать, питон огонь!
Последняя версия питона: 3.8.5.
Тестировалось на второй, поддержка которой в этом году заканчивается.
А в 3.8.5 какая производительность?
В оригинале статьи
The code takes about 7 hours on a modern computer to compute the matrix product, as shown by the first row (version 1) in Table 1, achieving only 0.0006% of the peak performance of the machine. (Incidentally, Python 3 requires about 9 hours for the same computation.)
Только 10е правило Гринспена (Любая достаточно сложная программа на Си или Фортране содержит плохо продуманную, плохо документированную, забагованную и медленную реализацию половины языка Common Lisp.) от этого никуда не девается — как только появляется ресурс для освобождения головы программиста от несущественных деталей, он на это используется.
Так нельзя сравнивать. Может, у вас комп в 3 раза быстрее.
Надо на одном и том же железе запускать и вашу реализацию и питоновскую.
Но вообще, похоже там опечатка где-то в размерах матрицы. Не верю, что решение на C будет 10 минут работать. По грубым прикидкам, должно быть раз в 10 быстрее даже на весьма слабом железе.
Не верю, что решение на C будет 10 минут работать.Видимо, причина в размере матрицы — он подобран так, чтобы точно не влезать ни в какие кэши и постоянно ходить в оперативную память. Там если потестить с разными размерами, получается не совсем теоретическая кубическая зависимости, график покруче растёт.
const N = 4096;
const N2 = N * N;
const A = new Float64Array(N2);
const B = new Float64Array(N2);
const C = new Float64Array(N2);
function fillRandom (M) {
for (let i = 0, len = M.length; i < len; ++i) {
M[i] = Math.random();
}
}
fillRandom(A);
fillRandom(B);
function index (i, j) {
return i * N + j;
}
console.time('mul');
for (let i = 0; i < N; ++i) {
for (let j = 0; j < N; ++j) {
for (let k = 0; k < N; ++k) {
C[index(i, j)] += A[index(i, k)] * B[index(k, j)];
}
}
}
console.timeEnd('mul');
// печатаем несколько произвольных элементов,
// чтобы оптимизирующий компилятор не счёл код мертвым
console.log(C[N]);
console.log(C[Math.round(N2/5)]);
console.log(C[Math.round(N2/2)]);
ИИ может хорошо проверить и построить по указке, но лично я бы не стал ему доверять именно создание чего-либо, особенно сложных систем.
А в будущем, думаю, люди будут писать код на каком-то абстрактном метаязыке, а умный компилятор будет генерить оптимальный код под нужную архитектуру с учетом всех ее особенностей.
Ирония в том, что под ваше описание подходят Java, Python… Да и С++. Возможно, что и Fortran.
В анализе забыли учесть один ключевой параметр — трудозатраты.
Да ПО стало медленнее, но это происходит за счет использования универсальных библиотек которые не учитывают нюансы кадого потенциального приложения но экономят время на разработку.
Иногда для ускорения чего-то трудозатраты минимальны — при наличии знаний и опыта, а вот разработчики универсальных (и не только) библиотек часто считают что наглядность и очевидность важнее скорости, поэтому реализуют что-то в лоб, чтобы всем кто работает над проектом (самой библиотекой) было понятно.
Проблема тут в том что библиотека делается для пользователей, а не для разработчиков библиотеки, но 90% её пользователей (а то и все 99%) никогда не посмотрят внутрь, надеясь на то что разработчики сделали всё максимально эффективно, а не наглядно.
Похоже, что единственного правильный путь — это дальнейшее усложнение компиляторов и среды исполнения, чтобы реальный алгоритм работы все дальше отходил от того, что написал юзер.
Возможно, даже с использованием ИИ и глобальной базы данных с информацией о всех открытых проектах мира.
По сути, первые шаги уже сделаны (взять тот же V8, который является шедевром инженерной мысли). Но надо больше. Вплоть до того, что использовать ресурсы добровольцев не на всякие поиски инопланетян, а на оптимизацию популярных библиотек, заменяя их код математически эквивалентным, но при этом абсолютно нечитаемым, но оптимальным, алгоритмом
Либы конечно отдельная тема
Я говорил именно о них. Простой пример — функцию подсчёта числа установленных бит в слове (32 бита) можно написать перебором битов (96 операций), а можно с помощью bit twiddling (12 операций). Первая будет понятна но медленна, если попадёт в очень длинный цикл, вторая будет непонятна но очень быстрой и в зависимости от конкретной задачи может сэкономить массу времени выполнения (в несколько раз, да — умножьте это на триллионы операций и потраченные ватты в датацентре).
Причём, вероятность того что именно эту функцию придётся править когда-либо стремится к нулю (для распостранённых архитектур, по крайней мере), то есть это фактически "write once, read never" код, а комментарий рядом с отсылкой на принцип действия и поддерживаемые архитектуры решит все сомнения для тех кому вдруг придётся там копаться.
А так да, если известно что какой-то кусок кода требует аж 10ms на выполнение (вместо возможных 10ns), но при этом ждёт ответа от сервиса который требует минимум 500ms на обработку — то это имеет мало смысла оптимизировать.
Я говорил именно о них. Простой пример — функцию подсчёта числа установленных бит в слове (32 бита) можно написать перебором битов (96 операций), а можно с помощью bit twiddling (12 операций
Либо даже в managed языке дёрнуть какой-нибудь BitOperations.PopCount, который под капотом вызывает нативную инструкцию для x86 / ARM и только в крайнем случае делает фоллбэк на софт-реализацию.
Более того, оптимальный код может быть даже проще и читабельнее. Несколько раз было, что наивный перебор занимает 100 строк навороченного рекурсивного кода, когда как решение через динамическое программирование кроме того, что быстрее, еще и занимает 20 строк кода+комментарии, где просто 2 вложенных цикла и простые вычисления.
Код даже читаемее, но чтобы его полностью понять надо, таки, знать ДП. Но пара ключевых слов в комментариях должны направить читающего на нужную статью в википедии.
В качестве примера исследователи приводят перемножение двух матриц 4096×4096. Они начали с реализации на Python как одного из самых популярных языков высокого уровня. Например, вот реализация в четыре строки на Python 2:
Какой-то наркоманский пример.
Если надо перемножать большие матрицы на Python — есть numpy. ( который для этого и придуман)
С тем же успехом можно было сравнивать трудоёмкость написания асинхронного веб сервера на nodeJS и ассемблере.
Я не к тому, что любое мобильное приложение надо писать на electron (привет Slack), просто инструмент — под задачу. ( хотя, очевидно, если все мобильные приложения будут писать на Rust люди с нормальной алгоритмической подготовкой — они будут сильно быстрее)
Если мне надо умножить две матрицы 1 — раз, чтобы получить результаты статистических расчетов по клиентам банка, возможно, самое простое —
import numpy
. Если надо их перемножать, чтобы в реальном времени управлять космическим кораблём — наверное — C\C++\Rust на процессоре с realtime-архитектурой.А numpy не на C реализован? Получаетя нечестно, говорим про питон, а привлекаем C ему в помощь.
И сколько numpy займет гигабайт на SSD диске, а он ведь не резиновый. И если нужно в нескольких средах работать, и каждая, скажем, по 5 гигабайт. А еще — Keras и Tensorflow новых версий видите ли, не работают с некоторыми проектами, и нужно еще и прошлые версии тоже установить. И т.д.
Как раз речь и идет об ожирении программ...
2. Numpy в 5 ГБ — Вы слегка загнули. Поставил — 67 МБ ( python3.8 ).
Много ли какой-нибудь TODO list перемножает матриц? ( если не брать видеосистему ОС, где всё оптимизированно, кстати, это ещё и к честности сравнения, т.к. большинство приложений используют ещё и api ОС, которую написали на C)
Некоторым программам — нормально жиреть, некоторым нет. Как я сказал выше — инструмент под задачу.
Это я о своем, пробовал машинное обучение на Windows, macOS, Linux. Работает нормально в Linux, в других системах модели получаются, но нерабочие.
А еще известно, что результаты научных расчетов на питоне могут различаться в зависимости от того, под какой ОС они получены. Из-за этого дискредитировано около сотни работ.
stackoverflow.com/questions/7295861/enabling-strict-floating-point-mode-in-gcc
Автор ссылается на старые авторитеты «деды нам показали», а сам пропагандирует уход в утопию, где вычислять нужно только идеально распараллеливаемые алгоритмы. Но деды, на самом-то деле, говорили об эффективности, а не о никому не нужной скорости «вообще».
Сколько читаю статьи на этом сайте — одни разговоры про моду, и почти ничего про реально нужное. Количество примитивно мыслящих убивает всё и вся, включая самих себя. Переходят на мобилки, на минимум движений, на минимум мыслей. И статьи вроде этой им кажутся «важными», «открывающими горизонты». Как же легко обманывать простодушных любителей мобилок…
Если бы я был заказчиком и мне бы сказали, что скорость загрузки моего сайта можно уменьшить до 120 мс, в то время как у моих конкурентов скорость загрузки 240 мс, поэтому при прочих равных я буду привлекательнее для потребителя, но за такую оптимизацию я должен заплатить 100 тысяч у.е., то я сразу пойму, что за эффективность тут имеется в виду.
А если мне скажут «За X тысяч у.е. мы улучшим взятый на потолке показатель эффективности на X%», то я, конечно, понятливо покиваю, а потом обращусь к тем людям, которые предлагали мне до этого скорость.
Когда мы переходим к более сложным системам, эффективностью будет являться более точное и качественное решение с минимальными затратами и то насколько оно удержит позицию такового. Реалии говорят — делать что-то под определённые нужды не получится в большинстве случаев, потому что для этого нужна целая инфраструктура, поддерживающая продукт от начала до конца, а конечная цена производимого будет напрямую зависеть от количества произведённого, если нет других технологий для создания более дешевой версии аппаратной части.
Так что на бумаге это всё отлично, а когда начинает работать, понимаешь что без мультизадачности никак. И ты либо потратишь время на расчёт отдельно взятых частей задачи, а потом всё это скомпилируешь, либо часть за тебя сделает язык, а тебе придётся просто привнести в это порядок и лоск.
Есть класс задач, где скорость не поможет никак.
А есть такие, где скорость не желательна.
Например ребёнку делают тест ДНК. Симулируют сценарии его будущей жизни(с 90% вероятностью) и радостно сообщают, что он не будет гражданином образованным, так как не способен.
Или оптимизировать скорость вывода синего экрана смерти и ждать 15 секунд ввода от пользователя, вместо…
крайне редкой задачи перемножения матриц
Разработчики игр и искусственного интеллекта с вами не согласятся.
Результаты:
Java 10: 68 sec.
.NET Core 3.1: 79 sec.
Даже не близко.
int[][] C = new int[4096][];
int[][] A = new int[4096][];
int[][] B = new int[4096][];
Array.Fill(A, new int[4096]);
Array.Fill(B, new int[4096]);
Array.Fill(C, new int[4096]);
var watch = System.Diagnostics.Stopwatch.StartNew();
for (int i = 0; i < 4096; i++)
for (int j = 0; j < 4096; j++)
for (int k = 0; k < 4096; k++)
{
C[i][j] += A[i][k] * B[k][j];
}
watch.Stop();
var elapsedMs = watch.ElapsedMilliseconds;
Console.WriteLine($"Time: {elapsedMs / 1000} sec.");
int[][] C = new int[4096][];
int[][] A = new int[4096][];
int[][] B = new int[4096][];
Arrays.fill(A, new int[4096]);
Arrays.fill(B, new int[4096]);
Arrays.fill(C, new int[4096]);
long startTime = System.nanoTime();
for (int i = 0; i < 4096; i++)
for (int j = 0; j < 4096; j++)
for (int k = 0; k < 4096; k++)
{
C[i][j] += A[i][k] * B[k][j];
}
long endTime = System.nanoTime();
long timeElapsed = endTime - startTime;
System.out.println("Execution time in sec : " +
timeElapsed / 1000000 / 1000);
А как работает fill
в Java и C#? А то в питоне такой код единожды создаст массив из 4096 элементов и скопирует ссылку на него 4096 раз, но это не то, что надо.
IL_0000: ldc.i4 4096 // 0x00001000
IL_0005: newarr int32[]
IL_000a: stloc.0 // C
IL_0000: Pushes a supplied value of type int32 onto the evaluation stack as an int32
IL_0005: Pushes an object reference to a new zero-based, one-dimensional array whose elements are of a specific type onto the evaluation stack.
IL_000a: Pops the current value from the top of the evaluation stack and stores it in a the local variable list at a specified index.
Вы уверены?
Из вашего листинга:
// [13 13 — 13 42]
IL_0021: ldloc.1 // A
IL_0022: ldc.i4 4096 // 0x00001000
IL_0027: newarr [System.Runtime]System.Int32
IL_002c: call void [System.Runtime]System.Array::Fill<int32[]>(!!0/int32[]/[], !!0/int32[]/)
Вот здесь вызывается Fill. Новый массив точно копируется целиком, а не лишь ссылка на него? В java переменные с типом "массив" — это ссылки на объекты "массив". В C# точно по-другому?
Посмотрите, не одинаковы ли строки в этих массивах.
Вообще, присваивание ссылки выглядит так:
// B = A;
IL_0033: ldloc.1 // A
IL_0034: stloc.2 // B
public static void Fill<T>(T[] array, T value)
{
if (array == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
}
for (int i = 0; i < array.Length; i++)
{
array[i] = value;
}
}
public static void Fill<T>(T[] array, T value, int startIndex, int count)
{
if (array == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
}
if (startIndex < 0 || startIndex > array.Length)
{
ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
}
if (count < 0 || startIndex > array.Length - count)
{
ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
}
for (int i = startIndex; i < startIndex + count; i++)
{
array[i] = value;
}
}
github.com/dotnet/runtime/blob/master/src/libraries/System.Private.CoreLib/src/System/Array.cs
Вам не кажется некорректным вот это поведение?
https://ideone.com/DDV9EC
using System;
public class Test
{
public static void Main()
{
// your code goes here
int[][] a = new int[5][];
Array.Fill(a,new int[5]);
printMatrix(a);
a[1][2]=3;
printMatrix(a);
}
private static void printMatrix(int[][]arr)
{
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr[i].GetLength(0); j++)
{
Console.Write(arr[i][j]+" ");
}
Console.WriteLine();
}
Console.WriteLine();
}
}
Вывод:
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 3 0 0
0 0 3 0 0
0 0 3 0 0
0 0 3 0 0
0 0 3 0 0
Это очень странное создание матриц.
Вообще-то многомерный массив на java выделяется как
double[][] a = new double[4096][4096];
а не
int[][] A = new int[4096][];
Arrays.fill(A, new int[4096]);
Ваш (некорректный) код мог целиком поместить данные в кэш, реальное умножение матриц менее дружелюбно к кэшу.
Не ленитесь выводить результат…
А все указанное время он занимался выделением памяти и ее очисткой?
Ну, уж выделение-то памяти для каких-то 12к объектов всяко быстрее 90 секунд работает. Не говоря уже о том, что там выделяются всего 6 объектов по 16-32кБ.
Но всё равно заведомо нулевые числа перемножать и суммировать — идея так себе.
Здесь основная проблема не в этом — на весь код всего 6 операторов new() — т.е. всего 6 объектов. Это неправильная матрица.
.method private hidebysig static void
Main(
string[] args
) cil managed
{
.entrypoint
.maxstack 5
.locals init (
[0] int32[][] C,
[1] int32[][] A,
[2] int32[][] B,
[3] class [System.Runtime.Extensions]System.Diagnostics.Stopwatch watch,
[4] int64 elapsedMs,
[5] int32 i,
[6] int32 j,
[7] int32 k
)
// [9 13 - 9 41]
IL_0000: ldc.i4 4096 // 0x00001000
IL_0005: newarr int32[]
IL_000a: stloc.0 // C
// [10 13 - 10 41]
IL_000b: ldc.i4 4096 // 0x00001000
IL_0010: newarr int32[]
IL_0015: stloc.1 // A
// [11 13 - 11 41]
IL_0016: ldc.i4 4096 // 0x00001000
IL_001b: newarr int32[]
IL_0020: stloc.2 // B
// [13 13 - 13 42]
IL_0021: ldloc.1 // A
IL_0022: ldc.i4 4096 // 0x00001000
IL_0027: newarr [System.Runtime]System.Int32
IL_002c: call void [System.Runtime]System.Array::Fill<int32[]>(!!0/*int32[]*/[], !!0/*int32[]*/)
// [14 13 - 14 42]
IL_0031: ldloc.2 // B
IL_0032: ldc.i4 4096 // 0x00001000
IL_0037: newarr [System.Runtime]System.Int32
IL_003c: call void [System.Runtime]System.Array::Fill<int32[]>(!!0/*int32[]*/[], !!0/*int32[]*/)
// [15 13 - 15 42]
IL_0041: ldloc.0 // C
IL_0042: ldc.i4 4096 // 0x00001000
IL_0047: newarr [System.Runtime]System.Int32
IL_004c: call void [System.Runtime]System.Array::Fill<int32[]>(!!0/*int32[]*/[], !!0/*int32[]*/)
// [17 13 - 17 65]
IL_0051: call class [System.Runtime.Extensions]System.Diagnostics.Stopwatch [System.Runtime.Extensions]System.Diagnostics.Stopwatch::StartNew()
IL_0056: stloc.3 // watch
// [18 18 - 18 27]
IL_0057: ldc.i4.0
IL_0058: stloc.s i
IL_005a: br.s IL_00a8
// start of loop, entry point: IL_00a8
// [19 18 - 19 27]
IL_005c: ldc.i4.0
IL_005d: stloc.s j
IL_005f: br.s IL_0099
// start of loop, entry point: IL_0099
// [20 18 - 20 27]
IL_0061: ldc.i4.0
IL_0062: stloc.s k
IL_0064: br.s IL_008a
// start of loop, entry point: IL_008a
// [22 17 - 22 46]
IL_0066: ldloc.0 // C
IL_0067: ldloc.s i
IL_0069: ldelem.ref
IL_006a: ldloc.s j
IL_006c: ldelema [System.Runtime]System.Int32
IL_0071: dup
IL_0072: ldind.i4
IL_0073: ldloc.1 // A
IL_0074: ldloc.s i
IL_0076: ldelem.ref
IL_0077: ldloc.s k
IL_0079: ldelem.i4
IL_007a: ldloc.2 // B
IL_007b: ldloc.s k
IL_007d: ldelem.ref
IL_007e: ldloc.s j
IL_0080: ldelem.i4
IL_0081: mul
IL_0082: add
IL_0083: stind.i4
// [20 39 - 20 42]
IL_0084: ldloc.s k
IL_0086: ldc.i4.1
IL_0087: add
IL_0088: stloc.s k
// [20 29 - 20 37]
IL_008a: ldloc.s k
IL_008c: ldc.i4 4096 // 0x00001000
IL_0091: blt.s IL_0066
// end of loop
// [19 39 - 19 42]
IL_0093: ldloc.s j
IL_0095: ldc.i4.1
IL_0096: add
IL_0097: stloc.s j
// [19 29 - 19 37]
IL_0099: ldloc.s j
IL_009b: ldc.i4 4096 // 0x00001000
IL_00a0: blt.s IL_0061
// end of loop
// [18 39 - 18 42]
IL_00a2: ldloc.s i
IL_00a4: ldc.i4.1
IL_00a5: add
IL_00a6: stloc.s i
// [18 29 - 18 37]
IL_00a8: ldloc.s i
IL_00aa: ldc.i4 4096 // 0x00001000
IL_00af: blt.s IL_005c
// end of loop
// [25 13 - 25 26]
IL_00b1: ldloc.3 // watch
IL_00b2: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Stop()
// [26 13 - 26 55]
IL_00b7: ldloc.3 // watch
IL_00b8: callvirt instance int64 [System.Runtime.Extensions]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()
IL_00bd: stloc.s elapsedMs
// [27 13 - 27 65]
IL_00bf: ldstr "Time: {0} sec."
IL_00c4: ldloc.s elapsedMs
IL_00c6: ldc.i4 1000 // 0x000003e8
IL_00cb: conv.i8
IL_00cc: div
IL_00cd: box [System.Runtime]System.Int64
IL_00d2: call string [System.Runtime]System.String::Format(string, object)
IL_00d7: call void [System.Console]System.Console::WriteLine(string)
// [28 9 - 28 10]
IL_00dc: ret
} // end of method Program::Main
Но именно .Net Framework библиотеки в .Net Core работать не будут.
Описанный код вполне может быть ускорен, распараллелен и векторизован умным анализатором, JIT, AI компилятором и чем-либо еще.
Никакой оптимизатор не знает с какой целью создан код, а без знания цели можно только оптимизировать очевидные вещи, которые хоть и помогают иногда, но всё же не далеко не всегда.
К примеру, если вы пишите функцию для поиска простых чисел, то никакой оптимизатор не "догадается" что это — поиск простых чисел, а как раз в таких случаях алгоритмы решают и дают мощный выигрыш по ресурсам.
Максимум возможностей оптимизатора — это эффективно реализовать то что вы написали на C/C++/Rust/etc в машинном коде, с учётом особенной процессора и архитектуры, по дороге выкинув лишнее (CSE, упрощение выражений, etc).
Основная же проблема — это чрезмерное обобщение и абстрагирование, которым буквально пронизаны большинство современных фреймворков и библиотек — классический случай "Jack of all trades, master of none".
Да, разработчикам проще и быстрее, но — ценой ресурсов, причём не их ресурсов.
Никакой оптимизатор не знает с какой целью создан код, а без знания цели можно только оптимизировать очевидные вещи, которые хоть и помогают иногда, но всё же не далеко не всегда.Сейчас DLSS умеет достраивать изображение в игре в реалтайме, повышая разрешение почти в два раза. Неужели рано или поздно оптимизатор не сможет понять, что конкретно в этом примере — умножение матриц, которое можно сделать с помощью AVX?
Аналогично с распараллеливанием — OpenMP и GCC уже два десятка лет обрабатывают #pragma omp parallel for, но аж в трех языках программирования и только с прямым указанием, что этот цикл можно параллелить.
Неужели рано или поздно оптимизатор не сможет понять, что конкретно в этом примере — умножение матриц, которое можно сделать с помощью AVX?
Без хинтов от разработчика — нет. Если AI начнёт строить догадки на тему "что имел в виду разработчик", то ничего хорошего, кроме плохого, из этого не получится, разве что он (AI) может проверить идентичность всех возможных входов всем возможным выходам исходного алгоритма (привет квантовым компьютерам).
Разумней подходить с другой стороны — на входе должна быть спецификация (что ожидаем на входе и выходе, ограничения по ресурсам etc), а жутко вумный компилятор подберет самые эффективные алгоритмы для реализации задачи на конкретной платформе, что-то типа "Ok Google, сделай-ка для меня приложение которое...".
Впрочем… если это будет когда-либо реализовано, да ещё надёжно (почти неизбежно, хотя вероятно и не в этом столетии) — программисты в массе своей уже будут не нужны.
Разве нельзя в компиляторе сделать прогон хотя бы циклов с попыткой их оптимизации?
В цикле на миллион проходов выполняется n++. Может ли компилятор пропустить его в пользу n=1000000?
Это как раз делается (иногда), но опять-таки, компилятор может лишь "догадываться" что важно именно значение "n" на выходе, а не побочные эффекты (время выполнения, нагрузка на кэш/память etc).
К тому же, с точки зрения банальной эрудиции здравого смысла (если не исключать его наличие у программиста) цикл на миллион повторений явно неспроста, если результат можно получить обыкновенным умножением.
Зря недооцениваете ИИ… К примеру, написал кто-то js либу, и заюзали ее 100500 проектов на гитхабе. Плюс, если спарсить код топ 1000000 сайтов мира, то там тоже на 10% она встретится.
То есть, ии может
1) проанализировать код этих сайтов и гитхаба
2) запустить код с гх и сайтов и отпрофайлить его со всех сторон
3) запустить ещё несколько миллиардов синтетических прогонов
4) создать оптимальный код для самых частых ветвей исполнения кода.
5) вывести правила, при которых оптимизацию запускать можно (чтобы не запустить оптимизацию на коде, который появится потом и будет использовать какой-то нестандартный грязный хак).
Может ли человек сделать что-то подобное?
Неужели рано или поздно оптимизатор не сможет понять, что конкретно в этом примере — умножение матриц, которое можно сделать с помощью AVX?
Не сможет. Вдруг такой порядок суммирования нужен специально, чтобы ошибка не накапливалась или не было переполнения? IEEE 754 на этот счёт специально говорит, что порядок вычислений, задаваемый программистом, свят и нерушим. Векторизация допустима только если программист её явно разрешил.
Аналогично с распараллеливанием
Да, совершенно аналогично. Внезапно, на компьютере, помимо, перемножения матриц, может параллельно что-то ещё быть запущено. Яростное желание некоторых особо умных компиляторов выжрать все доступные ресурсы компьютера — это оптимизация под конкретный вид рабочего процесса, но он не обязательно у всех именно такой. Например, я могу на 18 ядрах захотеть перемножать 18 пар матриц параллельно, а не каждую пару раскидывать на все ядра.
То есть компилятор компилятором, но в языке должна быть хотя бы в принципе возможность выразить подобные намерения, предположение, что пользователь всегда хочет максимальных флопсов — оно не 100% верное.
Буквально, только PVS Studio движется в подобном направлении
Программирование на ходулях? Если программист допускает такие ошибки — значит он идиот.
Я могу понять невнимательность, подсказки анализатора по код-стайлу и, например, использованию ссылок, где это возможно.
Но чтобы анализатор давал мне подсказки по архитектуре — нонсенс.
Лет 15-20 назад куча людей примерно тоже самое говорили про любые анализаторы в принципе. Так что я бы не зарекался… :)
Если программист допускает такие ошибки — значит он идиот.
Как показывает опыт PVS-Studio, этим идиотом может оказаться вообще кто угодно, в том числе и вы.
Напишу где-нибудь (x*x*3 — x*x*x*2), а мне анализатор сразу «вы изобрели smoothstep, может не делать велосипед, а взять библиотечную функцию?»
Ясное дело, в голову приходят только примеры, которые я знаю как оптимизировать. Но наверняка есть еще сотня таких, о которых не в курсе.
Если программист допускает такие ошибки — значит он идиот.
Или просто человек, существо биологическое, эмоциональное и погодно-пище-эмоцие-зависимый. И, значит, время от времени неизбежно ошибающийся.
если анализатор скажет «вы пытаетесь перебрать
Когда-то на Хабре писали про компилятор Фортрана. Он делал именно это.
Это нужен очень глубокий анализ, мне кажется.
Если узкое место — линейный перебор, то что можно предложить-то? Обычно это структуру данных нужно менять, а оно не всегда допустимо — эта коллекция может использоваться в других частях кода, где насчёт неё тоже есть какие-то свои предположения, которые замена способа хранения может нарушить.
Распараллеливание тоже не так просто, как кажется. Должна ли IDE анализировать, насколько далеко получится распараллелить, прежде чем задача перейдёт из compute-bound в memory-bound?
subcommande правильно говорит, такие вещи — это не уровень программиста, который должен выполнить задание. Это уровень архитектора, который задание выдал. Их нельзя подсовывать как точечные подсказки, должен быть язык описания требований и ограничений по масштабируемости на уровне конфигурационных файлов, иначе можно наворочать, что асинхронные параллельные части программы будут вырывать друг у друга канал памяти и тормозить ещё больше.
Вообще-то ещё проще: умножение матриц должно делаться вызовом функции умножения матриц, а не тремя циклами. Тогда это можно оптимизировать на уровне библиотек, не полагаясь на компилятор.
p.s. Воспроизводимость на колабе так себе — на разных ноутбуках результаты могут серьезно отличатся.
О, а colab не на сервере считает?!
Надеюсь, будущее за высокоуровневыми языками, позволяющими детали реализации оставлять компилятору, и хорошими оптимизаторами.
Раньше занимались оптимизацией т.к. не было другого варианта — или оптимизируй почти до идеала или железо не потянет твою софтину. Вспоминаю описанные на хабре эпопеи с оптимизацией игруль для PS1. А сейчас лишние когда лишние 8ГБ оперативки стоят 30 баксов, жесткий диск на терабайт ещё 50, то кто будет заморачиваться с оптимизацией? Когда на рынке процессоров, кол-во ядер удваивается каждые пару лет, чего вы хотели — идеальной оптимизации? Seriously?
P.S. Меня тоже напрягает данная ситуация, но ныть об этом толку нет — всё изменится только тогда когда мы упрёмся в физический потолок увеличения производительности. Только когда оптимизация станет экономически оправданной — только тогда о ней и будут думать.
Вместо появления новых функций, программа получает дизайнерский бантик, море «жира» и ноль нового функционала?
Как впрочем и те программы, которые я пишу.
Просто часто добавить новый функционал это много работы и это длится долго. А «бантик» сбоку прилепить часто дело пяти минут. Банально стайл поменял и вот тебе уже и совсем по другому выглядящая программа.
Посмотрите темпы роста однопоточной производительности процессоров. Возможно, для вас будет открытием что она почти не растет.
Так мы уже почти упёрлись в этот потолок. Остались считанные годы, думать пора заранее.
Без такого инструмента написание быстрых и одновременно многофункциональных программ экономически не оправданно. Можно сказать даже невозможно из-за особенностей человеческого мозга — человек может одновременно оперировать 5-6 сущностями, а для высокоэффективных программ необходимо много больше.
Авторы рекомендуют сконцентрироваться на главной задаче — повышении скорости выполнения программ, а не на скорости написания кода.
Осталось выяснить, кто за это заплатит.
За код который оптимизирует использование ресурсов придётся доплатить программисту, за код который просто работает — облачному провайдеру (или пожертвовать пользовательской базой которые недовольны скоростью), и не факт что второе будет дешевле первого, хотя бы потому что первое делается один раз (по крайней мере надолго), а второе по определению почти вечно (пока используется). Перенос всего в свой собственный дата-центр лишь слегка изменит объемы затрат, их структуру и распределение по времени, но результат скорее всего не изменится в проекции на всё время эксплуатации.
Библиотека: нарисовать_фигуры.
Функция "нарисовать_треугольник".
Функция "нарисовать_пентаграмму".
Код, написанный программистом:бла-бла-бла
нарисовать_треугольник
бла-бла-бла
Результат: внутри exe файла не будет функции «нарисовать_пентаграмму».Но что если дело обстоит так:
Библиотека: нарисовать_фигуры.
Функция "нарисовать_что-то_острое" (номер_фигуры: от 1 до 100500).
...
Если номер_фигуры = 30451, нарисовать треугольник
Если номер_фигуры = 30452, нарисовать пентаграмму
Если номер_фигуры = 30453, нарисовать кандибобрика
...
Код, написанный программистом:бла-бла-бла
нарисовать_что-то_острое(30451)
бла-бла-бла
то результат: внутри exe файла будет ВСЁ.Вот об этом надо подумать разработчикам компиляторов…
Вот другой пример: у вас есть мощная библиотека распознавания символов написанных от руки. Но вам нужны только цифры. Разработчик библиотеки об этом не подумал.
Библиотека может быть скомпилирована в dcu, dll или bpl. Все три варианта есть компиляция. Но первый вариант затем проходит через отсечение лишнего и включается в exe, а dll нет. С библиотеками bpl можно и так и так.
Кстати, более широкий чем нужно набор вводимых рукописных символов не только утяжеляет код, но и приводит к ухудшению качества распознавания.
Можно сконфигурировать проект, чтобы bpl хранились у конечного пользователя и подключались в рантайме. Это способ разгрузить ОЗУ и сократить время загрузки, если у пользователей разная специализация — не всем нужно всё. Именно так работает банковская система в крупнейшем негосударственном банке, где я работал.
Есть ещё один вектор развития — умная линковка. Если бы сборщик мог заглянуть в библиотеку и увидеть, что для константы 30451 достаточно использовать только одну функцию, и не стал тащить в сборку весь остальной хлам.
Очевидно, что формат библиотеки должен позволять такую оптимизацию. При компиляции библиотеки компилятор должен увидеть эти ветки и вынести их в заголовок, чтобы сборщик их использовал.
Кажется, нечто подобное уже реализовано (в gcc, rustc) и называется link-time optimization (LTO).
Теорема есть на этот счёт — в общем случае нельзя ничего сказать об алгоритме не запустив его. Так что остаётся лишь писать частные случаи в виде оптимизаций компилятора, линкора и проверок статических анализаторов.
Такое не будет работать, если используется рефлексия.
И разработчики SQL свой код ещё как оптимизируют.
На днях накрылся комп. Достал из кладовки старый ноут: Core 2 Duo, 2 гига, SSD. Зашёл на Авито и ужаснулся от тормозов. Те же объявления, те же картинки, те же сообщения, всё как и 5 лет назад, только тогда работало быстро, а сейчас медленно.
Я вотк стати в последнее время думаю что это вобще нифига не так. Юзеру ничего не хочется, работает как работается, но ему постоянно пытаются эти новые фичи продать
Немного странное на мой взгляд заявление. Можете привести конкретные примеры?
А то вот я смотрю на софт, которым я пользуюсь, и понимаю что мне конечно не нужны вот прямо все фичи актуальных версий, но приличная часть всё-таки нужна.
И на версиях скажем пятилетней давности я бы работать уже не хотел. Там уже не хватает как минимум приятных, а местами и даже прямо необходимых вещей…
А я не за какие фичи производительностью и не платил. Ну или точнее никакой потери производительности я не ощущаю, а большего мне и не надо.
А насчёт фич… Ну вот тот же Live Share у Visual Studio например на мой взгляд очень полезная штука. Особенно в нынешнее время. И нет, я его тоже не просил и даже не думал о таком до того как попробовал в деле.
Полагаю, проблема в том, что люди, которые пишут комменты на хабре, просто не попадают в ЦА "обычные юзеры". Я вот тоже много чем из новых фич последних версий софта пользуюсь, и обновления ОС, которые эти новые фичи приносят, мне чаще в радость, нежели наоборот. Но у меня ещё есть статистика, собранная за много лет установки ровно тех же обновлений на компы и телефоны родителей и жены… и вот они, как правило, вовсе не радуются новым фичам и не стремятся их изучать, как раз наоборот — большинство изменений приехавших в обновлении их огорчают и раздражают.
Навскидку, я бы сказал, что обратная реакция (радость после обновления) у них случается в 1-5% случаев, не больше. В целом это вырабатывает однозначно негативную реакцию на обновления, и если бы я их активно не пинал "надо обновляться из соображений безопасности", то они бы предпочли точечно обновлять 1-2 программы в год, после того как столкнутся с конкретной проблемой при их использовании (глючит или не поддерживает новые протоколы/форматы файлов)… и даже в этом случае их мечта в том, чтобы обновление принесло минимум других, видимых пользователю изменений, помимо нужного.
Иными словами, тезис бизнеса "юзерам нужны новые фичи" не совсем корректен. Новые фичи нужны для привлечения новых юзеров (т.е. самому бизнесу). А вот существующим юзерам эти новые фичи чаще поперёк горла, чем в радость.
И даже если мы возьмём сам андроид, то куча вещей по поводу которых с каждем апдейтом ругалась моя жена, она потом вовсю начинала использовать. Причём дай ей опять старый телефон со старым андроидом и тоже начинаются жалобы а ля «как здесь всё неудобно»…
У меня уже давно ощущение, что программы, игры, сайты разрабатывают те, кто этими программами, играми и сайтами не пользуется.
В коммерческой разработке почти всегда так. Программисты — это в основном пользователи IDE, а не своих программ. В идеале, процесс разработки должен быть построен так, чтобы в нём было юзабилити-тестирование продуктов.
Многие продукты из адобе клауд не работают на вин7. Позавчера работали, а сегодня уже нет. А за клауд, между прочим, просят денег. Нафига мне новые фичи, если я теперь не могу пользоваться даже старыми?
Недавний скандал с хромом, когда оказалось, что «выйти из гуглоакканта» совсем не выходит из него.
дропбокс постоянно добавляет новые ненужные (мне) фичи. А с некоторых пор андроидная версия разрешает только три устройства для синхронизации на базовом плане. А у меня больше. Поэтому использую версию примерно двухлетней давности. Айфонская версия тоже ругается, но хотя бы работает.
инстаграм постоянно добавляет какие-то новые перделки, которые ухудшают мой пользовательский экспириенс (который очень примитивен — тупо полистать ленту два-три раза в неделю, но и тут они умудрились сделать разражающие вещи). Несколько лет назад удалили из приложения карту, из-за чего собственно я и стал пользоваться инстаграммом.
За последние лет 15 очень редко было, что я про какие-то новые фичи в софте, которым пользуюсь, думал «о, молодцы, что добавили!». Обычно пофигу или даже «нахрена это надо».
Потом вы жалуетесь что где-то поймали баг. Потом вы жалуетесь что фирма урезает бесплатную версию своего продукта чтобы сподвигнуть людей за него платить. Какое это имеет отношение к новым фичам в софте?
A инстаграмм да, могу представить что их фичи вам нафиг не нужны, но я бы вас наверное и не назвал целевой аудиторией этого самого инстаграмма.
Какое это имеет отношение к новым фичам в софте?
Предложение «дропбокс постоянно добавляет новые ненужные (мне) фичи» вы не заметили? Про урезание новой версии это так, до кучи. Добавили? Добавили. Мне оно надо? Не надо.
но я бы вас наверное и не назвал целевой аудиторией этого самого инстаграмма.
Сейчас конечно нет. Только это не я не являюсь целевой аудиторией, а инстаграм стал ориентироваться на другую аудиторию.
В гугломапсах появилось дофигища новых фич, которые мне не только не нужны, но и мешаются (а линейку убрали и так и не добавили). Я тоже нецелевая аудитория? Телеграм вместо того, чтобы фиксить баги, добавляет всякие перделки.
Какой баг? Это про хром что ли? Это был как раз не баг, а фича.
В моём понимании это баг. Если это сделанно намеренно, то я бы сказал что это даже возможно причина для юридического наезда. Как минимум в отдельных странах.
Про урезание новой версии это так, до кучи. Добавили? Добавили. Мне оно надо? Не надо.
Естественно вам это не надо. Но это не добавление фич, а банальное зарабатывание денег.
а линейку убрали и так и не добавили.
Эээ, где убрали? Сейчас попробовал, всё работает. Может вы в lite модусе пытаетесь это делать?
Естетственно не все фичи нужны прямо всем людям. Такого я и не говорил. Но с другой стороны как-то странно утверждать что вот прямо все дпбавляемые фичи вот прямо вообще никому не нужны. Если бы они были бы никому не нужны, то их бы и не добавляли. Зачем на такое деньги тратить?
Но это не добавление фич,
Повторю еще раз: дропбокс постоянно добавляет новые ненужные (мне) фичи.
где убрали? Сейчас попробовал, всё работает. Может вы в lite модусе пытаетесь это делать?
В андроидном приложении. Давным-давно можно было тыкать пальцем по карте и показывалось расстояние между точками. Это выкинули то ли в 6-й, то в 7-й версии в 2014 (кажется) году.
Но с другой стороны как-то странно утверждать что вот прямо все дпбавляемые фичи вот прямо вообще никому не нужны.
Я такого не утверждал. Вы просили пример ненужных фич.
Исходный тезис вообще был, что юзеру новых фич не хочется, а не то, что ими никто не пользуется. Перделками телеграма я и сам пользуюсь, почему бы и не пользоваться, раз есть. Но они мне были не нужны и их мне не хотелось, мне важнее, чтобы пофиксили баги с отправкой видео, а не добавили возможность поставить в профиль видосик вместо жипега. Или в той же последней версии теперь в списке чатов показывается мелкая превьюшка картинки/видео из последнего сообщения. Ну кому такое вообще может быть нужно? Все равно ничего не разглядеть, а выглядит неопрятно.
Повторю еще раз: дропбокс постоянно добавляет новые ненужные (мне) фичи.
Повоторю: не все фичи нужны всем людям. Но вто добавляете ли дропбокс фичи не нужные никому? Или хотя бы ненужные большинству?
В андроидном приложении. Давным-давно можно было тыкать пальцем по карте и показывалось расстояние между точками. Это выкинули то ли в 6-й, то в 7-й версии в 2014 (кажется) году.
Зашёл сейчас на смартфоне и у меня всё работает.
Исходный тезис вообще был, что юзеру новых фич не хочется, а не то, что ими никто не пользуется.
Проблема только в том что куче юзеров новых фич не хочется ровно до тех пор пока они не увидят эти новые фичи у конкурента. И тут как в Алисе: надо бежать чтобы оставаться на месте…
не все фичи нужны всем людям.
С этим никто не спорит, такого никто не утверждал.
Но вто добавляете ли дропбокс фичи не нужные никому? Или хотя бы ненужные большинству?
Не, ну я же такого не могу знать.
Зашёл сейчас на смартфоне и у меня всё работает.
Блин, погуглил — действительно, вернули. Но так, что фиг наткнешься, если не знаешь. Раньше, правда, удобней было, но хоть так.
Вот и польза от сегодняшнего разговора :)
Когда прицепляете картинку, внизу четыре иконки: кроп, кисть, яркость/контрасть и т.д. и самоудаление. И в кропе там, где сейчас кнопка для отзеркаливания, был выбор пропорций.
PS. Видео тоже можно перед отправкой редактировать.
как раз и есть подтверждение, что новые фичи не нужны самим пользователям?
Нет, не вижу. О какой конкретной ненужной фиче в данном случае идёт речь?
Да все бы еще на XP сидели, если бы она поддеживалась.
Нет, не все. Я бы точно не сидел.
И офисом бы пользовались 97, но майкрософту же надо денег зарабатывать, как и всем производителям ПО, потому выпускают новый софт, «без которого вам не обойтись».
Кто вам мешает сейчас пользоваться 97-м офисом?
В том то и дело, что я тоже не вижу фичи, которую получил пользователь перейдя с xp на 10
И если лично вы её не видите, то её нет?
Но вобще, если 97 может открывать современные документы и там не будет ехать верстка, то я прям горд за него=)
Подождите, а разве поддержка новых форматов это не новая фича?
еще раз, я не говорю, что все бесполезно, я говорю что двигатель здесь продавец а не покупатель, и в связи с этим зачастую всеже изменения бесполезны для покупателя.
Кто-то заставляет кого-то покупать софт или вообще в принципе им пользоваться? Это для меня ново…
Подождите, а разве поддержка новых форматов это не новая фича?
А какие новые форматы открывает последний офис? Те самые с х в конце, которые он сам и придумал?
Для себя могу сказать что docx гораздо приятнее в использовании когда ты работаешь с ним через API. То есть получается практически для любой автоматизации.
Ты вот помнишь выкрики пользователей. «Хотим новые форматы, не совместимые с офис97!», я нет. Да даже «Хотим новые форматы!» не помню такого, пользовались тем что было.
Я мало того что их помню, я даже был одним из тех пользователей, которыe требовали эти самые новые форматы. То естъ любые форматы с котoрыми можно нормально работать через API.
Мне кажется было бы конструктивней говорить не «Ты не видишь, а он есть», а на вскидку некоторые киллер фичи привести, которые люди просили и которые нельзя было принципиально впилить в XP
Ну он например банально не поддерживал стакание иконок/программ на своём таскбаре. И чтобы это добавить надо было переделывать всю систему таскабара. А чтобы её переделывать это надо было уже кучу чего переделывать. С аккаунтами пользователей и правами у него была беда совсем и там всё тоже надо было глобально переделывать. С бэкапом. С UI у него была куча проблем. Полупрозрачные окошки и всё в этом роде. Да и вообще его тогда сравнивали с «яблочными» осями и он в сравнении часто проигрывал, а люди хотели себе часть фич оттуда.
И это только то что я могу вот так сразу припомнить…
С правами и юзерами там однозначно была беда. Может не для домашнего пользования, но для корпоративного уж точно. И вещи вроде «щас вам админ всё быстро настроит и установит по ремоту» там тоже нормально не работали. Если вообще работали.
И как сейчас это изменилось в десятке?
Под капот не лез, но по моему уже с висты или даже с семёрки перенос юзера с компа на комп у меня работате без проблем. На ХP это каждый раз были танцы с бубном.
А для них что вообще изменилось? При нормальной настройке пользователь как работал под ограниченной учёткой, так и работает.
У вас нет разбития на домены, юзергруппы и так далее? И нет разного доступа к разным вещам для разных групп пользователей? Ну и для прикола можете попытаться имплементировать Windows Аuthentication модуль для всего этого дела для ваших программ/сервисов под XP. Думаете выучите много новых интересных ругательств.
Если API это COM самого ворда/что там ещё в офисе, то как старые форматы могли мешать работе?
В очень дремучие времена все юзали qip вместо аськи потому, что он был заметно быстрее и без тонны рекламы.
Опять же, ты просто даже не знаешь сколько программ умерли не став известными потому что были тормозными.
Тут мы видим ошибку выжившего.
Да и вообще, есть прекрасный пример с флешем, который таки тормозил.
Проблема бездумного написания кода конечно тоже есть, но причина, по которой железо не поспевает за софтом, не в этом.
Миранда это конструктор на любителя, слишком много возьни.
Скайп перестал устраивать после продажи в Майкрософт, похорон всех изначальных технологий типа п2п, и опять же полезли реклама, тормоза.
Нельзя ругать ПО за то что оно ест слишком много ресурсов.
ПО не плохое, оно с индивидуальными особенностями.
Бодипозитивное ПО с особенностями не должно стоит дешевле, иначе это угнетение.
Нельзя выбирать ПО по отсутствию особенностей и требованиям к ресурсам.
Берут — потому что а) никто не предлагает другое за те же деньги б) государство никак не регулирует этот вопрос.
Я может не прав, но статья не о настоящем, пока железо со скрипом, но справляется
Вход в нашу индустрию для новичков прост и недавние новички создают давление на систему своими предпочтениями, выбирая одни инструменты вместо других.
Статья скорее о будущем, о том что «ребята, время халявы кончается, будущее где придется над кодом думать много и оптимизировать уже за следующей дверью, воспользуйтесь этим знанием и прокачайтесь»
Я давненько работаю в индустрии где ASIC это не матерное слово, а насущная необходимость, где код вынуждены вылизывать и клиентов со временем у таких компаний все больше и больше. Нет больше запросов — сделайте мне из говна и палок, все больше — «сделайте так чтоб на этом железе помимо вот этого еще поместился лунапарк и продажные женщины»
Еще 10 лет назад картина была принципиально другой.
Гении из Интела и АМД пока не справляются с тем что производит индустрия софта и тенденция такова, что ситуация становится все хуже.
Сейчас у многих людей в индстрии есть уникальный шанс — тренд понятен и нужно успеть подготовиться, а дальше дело каждого — адаптироваться или надеяться на лучшее. Кто прав покажет время.
Гении из Интела и АМД пока не справляются с тем что производит индустрия софтаГении из Интела и АМД справляются на отлично, они не виноваты в том, что индустрия софта зачастую производит откровенный отстой.
+ векторизация
+ интристики AVXА AVX — это не векторизация?
Например, Никола Дуза написал простое приложение для ведения списка дел. Оно работает в вашем браузере с HTML и Javascript. Как вы думаете, сколько зависимостей оно использовало? 13 000. Тринадцать. Тысяч. Пруф.Почему людям вообще приходит в голову для таких приложений подключать вообще какие-то зависимости? Меня выворачивает от самой идеи этого. Такое должно быть написано руками на ванилле.
Проблема, скорее не в программистах (они, как правило, фанатеют от оптимизации, иногда даже слишком), а в менеджменте, который не ставит подобных задач.
И часто почему-то перформанс ассоциируется со скалабилити. Нет, господа, скорость не всегда подразумевает 1000 серверов.
И таких примеров тьма, сорри накипело.
Например обфускатор от РейдГейта — не только запутывает код но и переводит «что то» на ассемблер — тем самым ускоряя работу дотнетовского экзешника
Если вы процессор, то свои регистры вы видите как желтые наклейки на столе, повернул голову и прочитал.
Кеш первого уровня выглядит примерно как взять со стола папочку, достать файлики, пролистать и выбрать из сотен нужный лист, на листе выбрать из тысячи строк нужную.
Кеш второго уровня заставляет вас встать и лойти до книжного шкафа, надо найти полку, книжку, страницу, прочитать, запомнить, поставить обратно и вернуться.
Кеш третьего уровня это как спуститься в подвал, где надо подвигать сундуки, открывать их, доставая и убирая книжки по очереди…
Оперативная память подобна городской библиотеке, пара остановок на автобусе, библиотекарь нам поищет требуемое и принесет. Но надо посидеть и подождать.
SSD накопитель подобен курьерской службе, примерно в течении суток-двух он доставит в библиотеку нужную книжку, далее в библиотеку надо сходить.
HDD диск подобен почте РФ, недели, а иногда и месяцы, надо ждать пока в библиотеку приедет нужная нам книжка.
Я вижу много претензий к большого размера библиотекам. Но ведь любой язык высокого уровня, это по сути, набор библиотек. Не важно, написан ли код собственноручно разработчиком (придуман или вспомнился), скопирован с учебника или сетевой библиотеки, или подлинкована библиотека и вызвана ее функция. Более того, качество кода в библиотеке должно быть выше за счет массовости и широкого распространения.
Быть может, когда нибудь машинный код нам будет писать нейросеть, по принципу состязательности — сделать то же самое, но быстрее.
Сейчас разница между регистрами и L1-кэшем, между кэшами и RAM не так уж велика — единицы и десятки крат, насколько я помню. SSD тоже приближаются к RAM, по крайней мере к RAM прошлых лет.
Быть может, когда нибудь машинный код нам будет писать нейросеть, по принципу состязательности — сделать то же самое, но быстрее.
Нечто подобное достигается с помощью profile-guided optimization или даже jit — код оптимизируется под требуемую архитектуру на основе замеров производительности. Хотя я не слышал, чтобы компилятор сам проводил бенчмарки вариантов кода и брал лучший.
к SSD NVME диску 0.5mс
Видел значения latency 20мкс. Реальную задержку случайного доступа не замерял.
Вносят заблуждение скорости передачи данных, это как увеличив число вагонов в поезде, мы увеличиваем скорость перевозки людей, но не отдельного человека.
В ряде случаев задержки не так важны. Например, в сценариях с последовательным доступом. Часть задержек случайного доступа нивелируется кэшированием (если есть много попаданий в кэш).
Быть может, когда нибудь машинный код нам будет писать нейросеть, по принципу состязательности — сделать то же самое, но быстрее.
Зачем писать код человеку — понятно. Чтобы потом код сам работал и зарплату не просил.
А зачем нейросети писать код? Если она сразу сама может задачу решить.
Сейчас нейросети писать код нужно, потому что ее человек так настроил, писать код (играть в го и так далее). Код человеку нужен чтобы была энергоэффективность и предсказуемость. То есть конкурирующие нейросети потратят на код условных 1000 человеколет и он будет совершеннее чем напишет человек и/или дешевле.
По мере появления стронгИИ код ей нужно будет писать по той же причине, что пишет сейчас человек — чтобы самой не работать, то есть чтобы оставалось больше ресурсов на внутренние задачи или на самоосознание.
Почти моментальный (а по меркам прошлого века — моментальный) расцвет Google Play и App Store с их миллионами программ.
Компьютер в прошлом веке был роскошью. Поэтому стоимость ПО в тысячи долларов особо не смущала.
Всё меняется. И много меняется не по закону Мура, не количественно. А качественно.
Но не процессор.
Если не пользоваться кэшем, из-за которого диски тормозят, резко кончится память.
Оперативная?
Давно такое видели лично?
Оперативная?
Давно такое видели лично?
Постоянно. Вот на текущем лаптопе:
$ free
total used free shared buff/cache available
Mem: 8014216 6960236 127192 605648 926788 187924
Swap: 24784888 8369108 16415780
Своп нарощен — раньше когда он был 8GB, регулярно заканчивался. Linux почему-то в этом случае неспособен даже быстро убить кого-то по OOM, впадая в позу вечного поиска смысла жизни с выжиранием процессора. Ждал полчаса, надоело.
Теперь с 24GB — своп регулярно подскакивает до 12GB, если начинает уж очень тормозить — перезапускаю кого-то.
Основные прожоры — firefox (по сумме) и почему-то Telegram (зачем ему столько?)
Предупреждая вопросы — c хромом ещё хуже, на моих шаблонах использования он ещё прожорливее, раза в два.
Может проблема тут? 8ГБ ни о чём сейчас.
Да, я знаю, и сам такое постоянно говорю. На десктоп меньше 32GB сейчас не ставлю. Десктопы я всегда сам себе комплектую, стандартные комплекты это безумие непонятно под какого потребителя. Но на лаптоп… поставщики железа уже много лет дают такие стандартные конфигурации, где RAM занижен вдвое от адеквата для таких характеристик, а если смотреть модели с 16GB в коробке и расширением минимум до 32, то у них и другие характеристики сразу выше, и цена. Это походный лаптоп, который 500$ и не сильно страшно даже случайно убить, расширять память ему не очень хотелось.
8ГБ ни о чём сейчас.Не впервые вижу это заявление. Вопрос простой — а сфига ли? Почему, чтобы пользоваться браузером, музыкальным проигрывателем и офисным редактором (типовое использование домашнего ПК), мне резко перестало хватать 1-2-4 гиг? Это или веб не туда развивается, или браузеры.
Объём памяти сильно зависит от шаблонов использования. Если не запускать много задач одновременно, 1-2-4 ГБ, возможно, хватит.
Веб развивается в сторону ускорения и усложнения веб-приложений. JIT, кэши, нескучные градиенты — это всё жрёт либо CPU, либо память. Т.к. увеличение объёма памяти более дёшево, чем увеличение скорости CPU, разработчики, скажем так, не стесняются агрессивно использовать все доступные объёмы памяти в погоне за скоростью.
Т.к. увеличение объёма памяти более дёшево, чем увеличение скорости CPU
Это в каком смысле?
Цены на память не падают с 2012 года, хотя процессоры в пересчёте на доллар, считаем, ускорились раза в 3 минимум (а с учётом инфляции и все 5).
Да, пока полно наглых прожор, которые считают, что они одни в системе и можно отхватить пару гигабайт просто так, но скоро их перестанут покупать.
Если не запускать много задач одновременно, 1-2-4 ГБ, возможно, хватит.
Почему "не запускать много задач одновременно"? Моё время на запуск/останов каждой я ценю больше, чем желания производителей, даже если из нескольких запущенных в конкретный момент работаю только с одной.
не стесняются агрессивно использовать все доступные объёмы памяти в погоне за скоростью.
Чувствуется. Ну скоро начнут получать по рыжим мордам.
Это в каком смысле?
Вы легко можете добавить память (хм, если материнская плата имеет свободные слоты), но процессор, работающий (в одном потоке) на 3х скорости от современных, так просто не купить.
Почему "не запускать много задач одновременно"?
Вы имеете в виду, "Почему бы не запускать задач больше, чем помещается в оперативной памяти?"? Так ведь своп медленнее оперативной памяти, и активное его использование — это довольно неудобно (медленно). Если нужно, чтобы было быстро — добавьте памяти либо предложите более эффективный алгоритм (или настройки) своппинга.
Вы легко можете добавить память (хм, если материнская плата имеет свободные слоты)
Да при чём тут слоты. Вот посмотрите на типовой лаптоп с поставкой сколько угодно RAM "из коробки" — сколько у него материнка тянет в пределе? В типовом варианте — всего лишь в 2 раза больше от этого значения. Это при том, что вообще адекватная конфигурация, соответствующая всему остальному железу, должна иметь как раз минимум вдвое RAM. А теперь возьмите любимый сайт — агрегатор цен разных магазинов и попробуйте выставить не только текущий объём RAM, но и предельный — сколько моделей отсеется, для которых даже вендоры не публикуют этот максимальный объём, и сколько останется?
Так что пусть оно даже формально дёшево (сколько там например 16GB DDR4 лаптопной — я вижу цены типа 80$), но вам поставили жёсткое ограничение — и страдайте себе в тряпочку. И сколько будет стоить переход на модель, где можно ставить больше? Там сразу прыжки цены по 200-300$ — это сильно больше, чем цена перехода, например, i3->i5.
Вы имеете в виду, "Почему бы не запускать задач больше, чем помещается в оперативной памяти?"?
Нет, я имею в виду именно так, как сказал: почему бы не запускать много задач одновременно?
Только потому, что обжоры хотят столько, что все не влезают в память? Ну так будут или свопиться, или вообще пойдут лесом. Поднять из свопа приложение, которое мне сейчас потребовалось — проще, чем запускать его.
Так ведь своп медленнее оперативной памяти, и активное его использование — это довольно неудобно (медленно).
Всё равно это лучше, чем рекомендуемый вами однозадачный режим.
Если нужно, чтобы было быстро — добавьте памяти либо предложите более эффективный алгоритм (или настройки) своппинга.
Извините, я в это "мышки, станьте ёжиками" не играю — тем более, когда за счёт большого свопа эти проблемы тривиально решаются. Вот тут уж точно я предпочту отщипнуть, например, 20GB от 128GB SSD, но получить устойчивую работу с плавным ухудшением количественных показателей, а не непредвиденно-рывочным убийством рабочих программ.
Вы легко можете добавить память (хм, если материнская плата имеет свободные слоты)
Да при чём тут слоты. Вот посмотрите на типовой лаптоп с поставкой сколько угодно RAM «из коробки» — сколько у него материнка тянет в пределе? В типовом варианте — всего лишь в 2 раза больше от этого значения. Это при том, что вообще адекватная конфигурация, соответствующая всему остальному железу, должна иметь как раз минимум вдвое RAM. А теперь возьмите любимый сайт — агрегатор цен разных магазинов и попробуйте выставить не только текущий объём RAM, но и предельный — сколько моделей отсеется, для которых даже вендоры не публикуют этот максимальный объём, и сколько останется?
Давайте отталкиваться от применений.
Если вы говорите о типовом ноутбуке, то берите и типового пользователя.
Типовой 8 Г. 4 Г — это уже крайне бюджетный вариант, точно не для комфортной работы на нём.
Для подавляющего большинства типовых пользователей — ноутбук используется для веб-серфинга, просмотра фильмов HD, не QHD, да как печатная машинка, еще как игровой компьютер.
С всеми задачами кроме игр задачей прекрасно справляется ноут с 8 Г.
Игры… Тут даже не в памяти дело, а в охлаждении, чего подавляющее большинство ноутов (даже игровых) не имеют.
Посему те нетребовательные к видеопроцессору игры, что тянет типовой ноут, им и 16 Г нормально, да и 8 Г терпимо, если видеокарта дискретная. Ну да, придется браузер закрыть.
Вот для комфортной работы, если тебе нужно что-то там запускать еще, Фотошоп, виртуальные машины, браузер, IDE и еще пару программ — тут да, нужно бы побольше.
Но это совсем не типовое использование (для большинства людей), посему не нужно под это применение рассматривать типовой ноутбук.
8ГБ ни о чём сейчас.
Не впервые вижу это заявление. Вопрос простой — а сфига ли? Почему, чтобы пользоваться браузером, музыкальным проигрывателем и офисным редактором (типовое использование домашнего ПК), мне резко перестало хватать 1-2-4 гиг? Это или веб не туда развивается, или браузеры.
А какая разница кто виноват, если лично вы ничего изменить не можете.
Еще лет 10 назад можно было себе позволять пользоваться браузерами на старых компактных движках…
Но сегодня вы, пожалуй, что и половину сайтов не увидите.
Давно такое видели лично?
Постоянно. Вот на текущем лаптопе:
-> % free
total used free shared buff/cache available
Mem: 33480392 16317828 16933212 17720 229352 17028832
Swap: 0 0 0
Ну это же плохой пример.
Неужели вы не видите?
Где то лет 10 назад 8 Г это было круто.
Сейчас, ну… Будет комфортно только под браузер разве что. И то если вы не любитель по 50 вкладок держать.
Ну это же плохой пример.
Неужели вы не видите?
Что плохого то?
Это же не сервер?
GUI, desktop?
По нынешним временам нормальные показатели затрат памяти.
У меня прямо сейчас столько же занято. Всего лишь браузер и IDE открыты.
Это нормальные показатели затрат памяти.
Но вот общего количества памяти маловато. Если, конечно, компьютер не «всего лишь пишущая машинка».
Linux не очень быстро работает со свопом, точнее, адски тормозит. Возможно, будет лучше отключить его.
8ГБ — обычно этого вполне достаточно для браузера. Если ваши шаблоны использования требуют больше памяти, то тут (какая банальность...) либо менять шаблоны использования, либо покупать память. Данные не ужмутся магическим образом, даже если вы этого хотите. Увы, это так не работает.
P.S. сколько у вас открыто вкладок? >50? >100?
Linux не очень быстро работает со свопом, точнее, адски тормозит. Возможно, будет лучше отключить его.
Про тормоза — источник в студию, пожалуйста. Отключение, очевидно, не метод.
Данные не ужмутся магическим образом, даже если вы этого хотите. Увы, это так не работает.
Мне и не требуется ужимание. Требуется, чтобы проблема от перегрузки нарастала мягко, а не непредсказуемым рывком в позу, из которой помогает только кнопка выключения.
P.S. сколько у вас открыто вкладок? >50? >100?
150-300. Не все сразу активированы, но некоторые могут быть крайне тяжёлые (как видео или хабростатьи на дофига комментариев).
Про тормоза — источник в студию, пожалуйста. Отключение, очевидно, не метод.
Личный опыт. Можете проверить. Как только ram закончится, без свопа linux начнёт прибивать процессы, не задумываясь.
Требуется, чтобы проблема от перегрузки нарастала мягко, а не непредсказуемым рывком в позу, из которой помогает только кнопка выключения.
Опять же, из личного опыта: windows работает описанным вами образом (с увеличением потребления памяти тормозит сначала понемножку, потом сильно). Linux сначала не тормозит, а при начале активного своппинга тормозит адски. Я сталкивался с этой проблемой лет 10 назад, а воз и ныне там, и решил её для себя добавлением памяти.
но некоторые могут быть крайне тяжёлые (как видео или хабростатьи на дофига комментариев).
Это не "крайне тяжелые". Бывают страницы с 3D графикой, где только текстур — под гигабайт.
>P.S. сколько у вас открыто вкладок? >50? >100?
150-300.
Имхо, это сверх разумных пределов. Примерно как держать всю городскую библиотеку на офисном столе. Есть же механизм закладок. Но, вроде бы, были какие-то браузерные расширения для выгрузки неактивных вкладок...
Личный опыт. Можете проверить. Как только ram закончится, без свопа linux начнёт прибивать процессы, не задумываясь.
Тем более — даже проверять не буду. Мне не нужно убийство "не задумываясь", мне нужно, чтобы выживали по максимуму.
Linux сначала не тормозит, а при начале активного своппинга тормозит адски.
Я с ним почти 20 лет работаю, и такого нет.
12309 — да, проблема. Но не то, что вы пишете.
Это не "крайне тяжелые". Бывают страницы с 3D графикой, где только текстур — под гигабайт.
Спасибо за ещё один аргумент в пользу моего решения.
Имхо, это сверх разумных пределов. Примерно как держать всю городскую библиотеку на офисном столе. Есть же механизм закладок.
Дополнительные бессмысленные движения, в большинстве случаев.
Мне и не требуется ужимание. Требуется, чтобы проблема от перегрузки нарастала мягко, а не непредсказуемым рывком в позу, из которой помогает только кнопка выключения.
FreeBSD
Что же касается алгоритмической оптимизации кода, то, увы, мне приходится заниматься этим чуть-ли на ежедневной основе, но, преимущественно, на SQL. То что замечательно работает на гигабайтной БД разработчика не редко оказывается совершенно неудовлетворительным на терабайтной продуктивной БД.
Как перезапустить закон Мура программными методами. Ускорение софта в тысячи раз