company_banner

С — не низкоуровневый язык

https://queue.acm.org/detail.cfm?id=3212479
  • Перевод


Ваш компьютер не является быстрой версией PDP-11


Привет, Хабр!

Меня зовут Антон Довгаль, я С (и не только) разработчик в Badoo.

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

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

Производители процессоров не одиноки в этом. Разработчики компиляторов C/C++ тоже внесли свою лепту.

Что такое язык низкого уровня?


Американский учёный в области компьютерных технологий и первый лауреат премии Тьюринга Алан Перлис дал такое определение:
«Язык программирования является низкоуровневым, если написанные на нём программы требуют внимания к несущественному».

Хотя это определение относится к С, оно не даёт понимания того, что люди желают видеть в языке низкого уровня. Различные свойства заставляют людей считать язык низкоуровневым. Представьте некую шкалу языков программирования с ассемблером на одном конце и интерфейсом к компьютеру Enterprise — на другом. Низкоуровневые языки «ближе к железу», тогда как высокоуровневые ближе к тому, как думают люди.

Чтобы быть «ближе к железу», язык должен предоставлять абстракции, которые соответствуют абстракциям целевой платформы. Легко доказать, что С был низкоуровневым языком в PDP-11. Последовательное выполнение программ, плоское адресное пространство, даже операторы пре- и постинкремента отлично ложились на режимы адресации PDP-11.

Быстрые эмуляторы PDP-11


Ключевая причина появления уязвимостей Spectre и Meltdown в том, что создатели процессоров не просто делали быстрые процессоры, а делали быстрые процессоры с интерфейсом PDP-11. Это важно, потому что позволяет программистам на С и дальше верить в то, что их язык близок к аппаратной части.

Код С предоставляет в основном последовательный абстрактный автомат (до C11 — полностью последовательный, если исключить нестандартные расширения). Создание нового потока — это вызов функции библиотеки, операция, которая довольно дорога. Поэтому процессоры, желая продолжать выполнять код C, полагаются на параллелизм на уровне команд (instruction-level parallelism, ILP). Они анализируют соседние операции и выполняют независимые параллельно. Это значительно усложняет процессоры и приводит к увеличению потребления энергии, но позволяет программистам писать по большей части последовательный код. В противоположность этому графические процессоры (GPU) достигают высокой производительности другим путём: они требуют написания параллельных программ.

Высокий параллелизм на уровне команд является прямой причиной появления Spectre и Meltdown. Современный процессор Intel выполняет до 180 инструкций одновременно (в отличие от последовательной абстрактной машины C, которая ожидает, что предыдущая инструкция выполнится перед тем, как начнётся выполнение следующей). Типичная эвристика кода на С показывает, что есть одно ветвление в среднем на каждые семь инструкций. Если вы хотите держать конвейер инструкций полным, то вам нужно угадать следующие 25 ветвей. Это, в свою очередь, добавляет сложности — неправильно угаданную ветвь процессор сначала просчитает, а потом результаты расчётов выбросит, что негативно влияет на энергопотребление. Эти выброшенные данные имеют видимые косвенные результаты, что и было использовано в атаках Spectre и Meltdown.

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

Рассмотрим ещё одну фундаментальную часть дизайна С: плоскую память. Её не существует уже пару десятилетий. Современный процессор зачастую имеет три уровня кеширования между регистрами и основной памятью, чтобы таким образом уменьшить время на обращение к последней.

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

Оптимизация С


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

К сожалению, с помощью простой трансляции нельзя получить быстрый код из С.
Архитекторы процессоров прикладывают героические усилия для создания чипов, которые могут выполнять код на С быстро. Но уровни быстродействия, которые ожидают увидеть программисты, достигаются только с помощью невероятно сложных оптимизаций, выполняемых компилятором.
Компилятор Clang (включая соответствующие части LLVM) — это около 2 млн строк кода. Для анализа и трансформации кода, которые необходимы для ускорения С, нужны около 200 000 строк кода (без учёта комментариев и пустых строк).

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

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

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

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

Рассмотрим две базовые оптимизации, которые производит компилятор C: SROA (scalar replacement of aggregates, скалярная замена агрегатов) и размыкание цикла.

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

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

В С неинициализированная переменная имеет неопределённое значение, которое может быть разным при каждом обращении. Это важно, поскольку позволяет реализовать ленивую переработку (lazy recycling) страниц памяти. Например, во FreeBSD реализация malloc() сообщает системе, что страницы более не задействованы, а система использует первую запись в страницу как доказательство того, что это не так. Обращение к только что выделенной памяти может получить старое значение, тогда операционная система может повторно использовать страницу памяти, после чего заменить её на заполненную нулями страницу при следующей записи в другое место страницы. Второе обращение к тому же месту страницы получит нулевое значение.

Если в условии используется неопределённое значение, то результат тоже не определён — может произойти что угодно. Представьте оптимизацию по размыканию цикла, где цикл выполняется ноль раз. В оригинале весь цикл является мёртвым кодом. В разомкнутой версии теперь есть условие с переменной, которая может быть не инициализирована.
В результате мёртвый код может быть преобразован в неопределённое поведение. Это только одна из многих оптимизаций, которые при более тщательном исследовании семантики C оказываются ненадёжными.

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

Понимая C


Одним из базовых атрибутов языка низкого уровня является то, что программисты могут легко понять, как абстрактная машина языка переносится на физическую машину. Это определённо было так на PDP-11, где выражения на C транслировались в одну или две инструкции. Аналогично компилятор клал переменные в слоты стека и преобразовывал простые типы в понятные для PDP-11.

С тех пор реализации C стали гораздо сложнее — для поддержания иллюзии того, что C легко переносится на аппаратную платформу и работает быстро. В 2015 году результаты опроса среди программистов на C, авторов компиляторов и членов комитета по стандартизации показали, что существуют проблемы с пониманием C. Например, этот язык позволяет реализации добавлять выравнивание в структуры (но не в массивы), чтобы гарантировать, что все поля правильно выровнены для целевой платформы. Если вы заполните эту структуру нулями и потом укажете значение некоторым полям, будут ли в битах выравнивания нули? Согласно результатам опроса, 36% были уверены, что будут, а 29% опрошенных не знали ответа. В зависимости от компилятора и уровня оптимизации это может быть правдой (или нет).

Это довольно тривиальный пример, однако многие программисты или дают неправильный ответ, или не могут ответить вовсе.

Если добавить указатели, семантика C становится ещё более запутанной. Модель BCPL была довольно проста: все значения являются словами. Каждое слово — это или данные, или адрес в памяти. Память — это плоский массив ячеек с индексацией по адресу.

Модель С позволяет реализацию для разных платформ, включая сегментированные архитектуры, где указатель может состоять из ID сегмента и смещения, а также виртуальные машины со сборщиком мусора. Спецификация C ограничивает разрешённые операции с указателями, чтобы избежать проблем с такими системами. Ответ на Defect Report 260 содержит упоминание происхождения указателя:
«Реализации могут следить за происхождением набора битов и обращаться с содержащими неопределённое значение иначе, чем с теми, которые содержат определённое. Они могут обращаться с указателями по-разному в зависимости от их происхождения, даже если они одинаковы с точки зрения их битового значения».

К сожалению, слово «происхождение» отсутствует в спецификации C11, поэтому компиляторы сами решают, что оно означает. GCC и Clang, например, отличаются в том, сохраняет ли своё происхождение указатель, который конвертировали в целое и назад. Компиляторы могут решить, что два указателя на результаты malloc() при сравнении всегда дают отрицательный результат, даже если они указывают на один и тот же адрес.

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

При наличии подобных проблем сложно ожидать от программиста полного понимания того, как программа на C транслируется на соответствующую архитектуру.

Представляя процессор не для C


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

Есть множество примеров архитектур, которые не были сфокусированы на традиционном коде C и из которых можно черпать вдохновение. Например, такие ориентированные на многопоточность процессоры, как Sun/Oracle UltraSPARC Tx, не требуют столько кеша, чтобы держать занятыми свои исполнительные устройства. Исследовательские процессоры расширили этот концепт до очень большого количества аппаратно-планируемых потоков. Ключевая идея состоит в том, что с достаточным количеством потоков процессор может приостановить те потоки, которые ожидают данных, и наполнить исполнительные устройства инструкциями из других потоков. Проблема же состоит в том, что программы на C обычно имеют очень мало потоков.

ARM’s SVE (Scalar Vector Extensions, скалярные векторные расширения) — ещё одна аналогичная работа из Беркли, которая предлагает взглянуть на улучшенный интерфейс между программой и аппаратным обеспечением. Обычные блоки векторизации реализуют операции с векторами фиксированного размера и ожидают, что компилятор адаптирует алгоритм к указанному размеру. В противоположность этому интерфейс SVE предлагает программисту самостоятельно описать уровень параллелизма и ожидает, что аппаратная часть самостоятельно адаптирует его к имеющимся в наличии исполнительным устройствам. Использовать это в C сложно, потому что автовекторизатор должен рассчитать параллелизм на основании циклов в коде.

Кеши имеют большой размер, но это не единственная причина их сложности. Протокол поддержки когерентности кеша — одна из сложнейших составляющих современного процессора. Большая часть сложности появляется из-за того, что нужно поддерживать язык, в котором данные могут быть одновременно разделяемыми и изменяемыми. В качестве обратного примера можно привести абстрактную машину в стиле Erlang, где каждый объект или локальный, или неизменяемый. Протокол когерентности кеша для такой системы имел бы только два случая: изменяемые данные и разделяемые данные. Кеш программного потока, который перенесли на другой процессор, нужно явно инвалидировать, но это относительно редкая операция.

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

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

В сфере разработки программного обеспечения есть миф о том, что параллельное программирование — это сложно. Алан Кэй был бы очень удивлён, услышав это: он научил детей использовать модель акторов, с помощью которой они писали программы на более чем 200 потоков. Это неизвестно и программистам на Erlang, которые часто пишут программы с тысячами параллельных компонентов. Более правильно говорить, что параллельно программирование сложно на языке с абстрактной машиной, подобной C. И если обратить внимание на преобладание параллельного аппаратного обеспечения (от многоядерных процессоров до многоядерных GPU), то это просто ещё один способ сказать, что C не подходит для современного аппаратного обеспечения.

Badoo

219,12

Big Dating

Поделиться публикацией
Комментарии 293
    +6
    Современный процессор Intel выполняет до 180 инструкций одновременно (в отличие от
    последовательной абстрактной машины C

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

      0
      Отчасти да, отчасти нет. Библиотеки на ARM'е (на сотовых) — обычно перекомпилированные версии x86 библиотек… но они всё равно написаны на C.
        +1

        Числодробилки часто оптимизируют под VFP и NEON, так что там тоже уже платформо-зависимый код на асме или интринсиках

          0
          Так всегда было. И всегда этого «платформно-зависимого кода» было несколько процентов.
      +27
      С таким же успехом и ассемблер можно назвать высокоуровневым — все перечисленные в статье аргументы относятся и к нему (параллельное исполнение, кеши, выравнивание и т.п.). Но ближе к железу ничего нет. Поэтому все эти доводы весьма сомнительны.
        +22

        Ассемблер в x86 — это тоже высокоуровневый язык. Автор оригинальной статьи нацеливается на C (один из двух-трех языков, которые дожили от 70х до наших времен, и наверняка самый из них популярный), но большинство аргументов применимы ко всем языкам подобной идеологии, включая даже ассемблер и машинный код. В современном x86 процессоре есть встроенный оптимизирующий компилятор, который преобразует "высокоуровневый" ассемблер во внутренний низкоуровневый — включая SSA (переименование регистров) и параллелизацию. Посыл статьи (если отбросить C-специфичные вещи про выравнивание, неопределенные биты и тд) в том и был, что C (и все другие похожие языки) был простым языком, который напрямую ложился на реальное железо, а теперь инженеры пытаются всячески вбить новое железо (которое имеет принципиально другие допущения!) в видение мира старого языка (а разработчики компиляторов в то же время пытаются как-то приспособиться к новому железу, которое пытается выглядеть старым). Строго та же фигня происходит и с, к примеру, архитектурой ОС — до сих пор программы притворяются, что весь компьютер принадлежит им, а ОС всячески им в этом потворствует ценой приличных накладных расходов. Обратная совместимость — главное зло мира...

          +5
          Да, но в данном контексте низкоуровневых языков (позволяющих напрямую манипулировать кешем, к примеру) не существует в принципе, и тогда делить на высоко/низкоуровневое вообще нечего. В реальности же, если расположить существующие языки лесенкой, то С стоит на втором месте, после ассемблера, никаких фортранов и эрлангов там близко нет (автор их захотел втащить на пьедестал, как мне показалось). Кстати, некоторые аргументы вообще ложные, например про выравнивание.
            +3

            Правильно, нечего их делить, но делят же. Тут вот ниже про микроконтроллеры упомянули правильно — они примерно соответствуют тем машинам, для которых разрабатывался C. В прицеле на них C будет низкоуровневым, а Java — не очень. В прицеле x86/ARM/POWER — какой-то большой разницы между С и Java уже нет.
            Про фортран -он такой же, как и C, просто автор еще и выискивает в C любые вещи, которые мешают компилятору делать переход 1-1 из исходного кода в машинный (как то выравнивание и алиасинг). Эрланг же был упомянут как пример принципиально другой идеологии (многопоточного) программирования, которая может казаться странной и сложной для приверженца С-подобных языков и POSIX-подобной share-everything многозадачности, но современное железо может оказаться больше заточенным под модель эрланга, чем под модель C.
            Большая часть этой статьи — это вопль в пустоту о том, что если делать все с нуля — включая парадигму программирования, которая учитывает текущие реалии в железе — то можно сделать процессор значительно проще, дешевле, холоднее и быстрее тех, что есть сейчас. Но такой процессор не сделают, потому что программы на C на нем будут работать медленно.

              0
              Просто нет языков под специализацию процессора. Вот была статья про Мультиклет — на который С-парадигма нормально не ложится. Но не ложится и ничего более из языков.

              Еще и мир устроен лентяями — стоит попробовать спросить J-скриптера, во сколько тактов развернется его лямбда?
                0

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

                  0
                  Да конечно, теоретически смогут. Если на этом (любом) языке смогут быть явно вычислены/выражены условия параллелизма конкретного процессора.

                  Иначе язык отдает это на откуп компилятору, который ...., дом который построил Джек
                    +2
                    Этого недостаточно. Нужно еще знать, где параллелизм оправдан, а где — нет, и какой гранулярности.
                    +2

                    Только не в JS. В этом языке функция map явно однопоточна: стандарт предписывает вызывать переданную функцию строго последовательно...

                    –3
                    Если что то тормозит, запускай профайлер.
                    Кстати сегодня он мне сэкономил тучу времени. Получать культуру в цикле было плохой идеей.
                    var ci = (CultureInfo)CultureInfo.CurrentCulture.Clone();
                      +2
                      А мне отчего-то кажется, что чистое ФП с нестрогой моделью вычислений (это которую ленивой обзывают иногда) на мультиклетоподобные архитектуры отлично ляжет.
                        0
                        Статью прочитал, а комментарии почти нет. Вопрос к вам и к знающим людям: принимая во внимание все вышесказанное, можно ли сделать какой-нибудь функциональный язык, который будет решать задачи принципиально быстрее, чем С, и будет в каком-то смысле низкоуровневым? Имеются в виду как бенчмарковские задачи вроде сортировок, так и реальные задачи вроде HTTP-сервера.

                        Потому что если я правильно понимаю, сейчас ФП сильно проигрывает в производительности, а с учетом оптимизаций процессора для С – даже в задачах, которые легко распараллелить.
                          +2
                          Смотря как определено «быстрее».

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

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

                          А что до разницы в производительности ­— ну, это зависит. У меня в практике встречались задачи, где хаскель уделывал С++ (с учётом замечания выше о ресурсах), и встречались задачи, где С++ уделывал хаскель на несколько порядков. В последнем случае просто было очень много данных и очень много последовательных циклов по ним.
                    +2
                    Существуют расширения для С (CUDA, например) которые умеют работать с различными уровнями памяти на GPU — shared, local, global. Что в принципе схоже с организацией кешей в x86 и x64.
                      +1
                      На самом деле задач, где имеет смысл использование shared памяти на gpu не так уж много. Nvidia в свое время сделало кэширование global памяти, такое же как в обычных процессорах, но потом в один прекрасный момент молча это выпилили. В результате производительность в конкретной задаче конкретно просела. В замен они добавили специальную инструкцию, для чтения глобальной памяти, которая гарантировала попадание данных в кэш. Но только это работало для константных данных и следить за тем, чтобы они не менялись должен был сам разработчик.
                        0
                        задач, где имеет смысл использование shared памяти на gpu не так уж много
                        Расскажите, пожалуйста, по-подробнее с этого места. Какого типа операции или задачи над данными на GPU не имеет смысла выполнять с использованием shared memory? И какие имеет смысл?
                          +1
                          По моему опыту, не имеет смысл использовать shared memory в большинстве задач, потому что просто нечего там хранить: прочитал элемент из global или текстуры, обработал, сохранил туда же или в другой буфер.
                          Классическим примером, где нужно использование shared, является перемножение матриц, там это дает большое ускорение, но это весьма специфический пример.
                          В своих задачах я использую shared memory в основном при всякой редукции, тут она нужна чисто для обмена данными между потоками в блоке. Но для этого в той же CUDA есть и другие механизмы, можно обойтись и без нее.
                          Еще shared memory нужна, когда каждому потоку нужен какой то локальный буфер для своих вычислений. Но здесь размер буфера получается весьма ограничен, да и честно сказать это не очень эффективно. Если в задаче требуется буфер, то обычно ее достаточно сложно реализовать на gpu.
                          Больше что-то ничего не приходит в голову, для чего может shared memory понадобиться. Скорее в остальном это специфические задачи.
                            0
                            А вот у меня обратный случай — большинство задач связано с некоторым состоянием, которое претерпевает множество изменнеий в процессе работы приложения. При этом это состояние выгодно разбить на кусочки и хранить в shared memory. При этом если размер состояния не помещается в shared — то практически всегда есть возможность реализации ручного кеширования части этого состояния.
                            >> Скорее в остальном это специфические задачи.
                            Да.
                    –10
                    Обратную совместимость я бы лучше заменил банальным словом «лень»…
                    Обратная совместимость — продукт нежелания миллионов программистов переписывать миллиарды строк кода(знаменитое Java-вское «написано однажды — работает всегда»). Каждому из нас не хочется этого делать… Но проблема тут не в программисте, а в языке, на котором написан код.
                    Язык С, как и все его компилируемые наследники(C++, Java, ..., но не Python, хотя там свои проблемы) в нынешние дни имеют ряд коренных недостатков, которые были не видны людям из далеких 70-x. Например, в С/C++ нельзя просто взять и написать ассемблерные вставки или функции. Это просто отсутствует в стандарте. И что прикажете с этим делать? А ведь даже такая малая стандартизируемая возможность в корне может ускорить выполнение кода…
                      +7
                      Обратную совместимость я бы лучше заменил банальным словом «лень»
                      А когда этим заниматься миллионам программистов, если им надо работать по 8+ часов в день, что бы семью кормить?
                      Но проблема тут не в программисте, а в языке
                      Нет, проблема в суровой реальности — людишкам, которые не бум-бум в компуктерах, нужны новые интернет-магазинчики, а не стоп-кадр на 10 лет, что бы переделать все по-нормальному.
                      Например, в С/C++ нельзя просто взять и написать ассемблерные вставки или функции.
                      Можно практически во всех популярных реализациях.
                      А ведь даже такая малая стандартизируемая возможность в корне может ускорить выполнение кода…
                      В 0.001% случаев, потому что компиляторы уже давно умнее нас.
                        +2
                        Можно практически во всех популярных реализациях.

                        Да, но в Стандарте понятие ассемблерных вставок, ассемблера вообще и прочих FFI не описано.

                        Но это в каком-то смысле буквоедство.
                          +5
                          Да, но в Стандарте понятие ассемблерных вставок, ассемблера вообще и прочих FFI не описано.

                          Ну как же. Раздел 9.9 как раз и описывает понятие ассемблерной вставки:image
                            0
                            Нет, понятие ассемблерной вставки он не описывает (по крайней мере, в обычном человеческом понимании ассемблера). Он описывает ключевое слово и контекст в грамматике (ну, я там ниже про это писал).

                            Если в вашей реализации string-literal будет кодом на, я не знаю, хаскеле, то это всё равно будет стандартом считаться ассемблерной вставкой. Какой-то намёк на inline assembly там только в примечании, но оно никого ни к чему не обязывает.
                              0

                              Вы путаете значение слова "понятие" с чем-то другим.

                          0

                          deleted

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

                            Ну, может и без стоп-кадра возможно… Например, начать с серверов… Сделать ЯП мимо C, под современный проц, и переписать на нём BEAM (виртуальную машину Erlang). Кто бы это только профинансировал?..

                              +1
                              Для начала надо будет переписать на новом ЯП операционную систему — ибо она точно написана на С. Иначе все это полумеры и косметика над трупом. :)
                            +4
                            Например, в С/C++ нельзя просто взять и написать ассемблерные вставки или функции. Это просто отсутствует в стандарте.
                            Стандарт описывает и разрешает ассемблерные вставки. Единственное что он не описывает, так это синтаксис внутри самой вставки.
                              +2

                              Стандарт по большому счёту резервирует ключевое слово asm и кусок грамматики вокруг него. Не описывает он не только синтаксис, но и семантику: необходимо ли иметь доступ к локальным/глобальным переменным, необходимо ли указывать, что какой-то регистр портится/не портится вставкой, и так далее.

                                +1
                                Да. Я в курсе. Но речь шла не об этом. Речь была о том, что:
                                … Это просто отсутствует в стандарте. ...

                                Как сказали выше, каждый современный компилятор подерживает вставки по-своему. Документации об этом навалом в свободном доступе.
                              +9
                              Обратная совместимость — продукт нежелания миллионов программистов переписывать миллиарды строк кода(знаменитое Java-вское «написано однажды — работает всегда»).

                              Да не, у программистов никакого нежелания нет. платите деньги — и вам все перепишут.

                              0
                              до сих пор программы притворяются, что весь компьютер принадлежит им, а ОС всячески им в этом потворствует ценой приличных накладных расходов

                              А как надо?
                                0

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

                                  +1

                                  Я имел в виду и саму вытесняющую многозадачность с внезапным прерыванием выполнения и сбросом контекста выполнения куда-то в память, и раздельные адресные пространства для приложений, которые влекут за собой еще большие накладные расходы на переключение, и переходы в ядро и обратно, и прочие "особенности" привычных нам ОС.
                                  Как надо? Не знаю, я сам заядлый C++ программист ) Но подозреваю, что куда-то в сторону managed языков и кооперативного шедулинга мелких задач/вытесняющей многозадачности, но не в любой точке кода, а в определенных точках останова (VM может гарантировать, что одна программа не перетрет другую и не захапает себе все время)

                                    +1
                                    Дайте оценку ресурсам, теряемым современными компьютерами/ОС от вытесняющей многозадачности, и сравните их с ресурсами, необходимыми для полной замены существующих систем.
                                      0

                                      Встречное предложение — оцените ресурсы, потраченные на борьбу с имеющимися ОС. Сколько человеко-лет ушло на написание TBB и всех ему подобных диспетчеров (включая что-то похожее в каждом первом игровом движке), которые суть подменяют встроенный в ОС диспетчер потоков на свой диспетчер задач — потому что встроенный механизм переключения потоков слишком накладный? Сколько ушло на разработку lockless структур — потому что локи/спинлоки использовать нельзя, потому что а вдруг вытеснят в критической секции?

                                        +2
                                        Когда вы пишете «слишком накладный» и не пишете, что именно это значит, то это совершенно бессмысленное выражение. То ли это 0,1%, то ли 99%. Кому-то суп жидок, кому-то жемчуг мелок.
                                        Неважно сколько человеко-лет ушло на написание того, что вы перечислили. Важно, что априори оно много меньше того, сколько человеко-лет понадобится на реализацию ваших предложений.
                                        Когда действительно большому количеству пользователей (в данном случае программистов) что-то становится действительно необходимым, то появляется библиотека, фреймворк и т.п. Этот ваш intra-app «диспетчер задач» по сути реализация user-level threads, давно известной концепции. Раз нет одной или нескольких популярных реализаций такой концепции, следовательно это проблемы явного меньшинства, которое и вынуждено строить свои велосипеды. А менять ВСЁ ради решения проблем меньшинства как-то нерационально.
                                          0

                                          Реальный пример — наивная реализация flow based programming, где каждая нода — это поток, обмен друг с другом сообщениями через очереди. Делаем несколько тысяч нод-потоков, запускаем на большой машине с кучей ядер, набрасываем миллионы сообщений в секунду и получаем >50% накладных расходов чисто на переключение потоков.
                                          Про явное меньшинство — TBB, Cilk, часть OpenMP, Microsoft's PPL/Concurrency, встроенный в OS X GCD, встроенный в Go goroutines, встроенные в Erlang процессы, TAP в .NET, десятки самописных для разных приложений и библиотек. Как только мы переходим от use case "несколько долгоживущих независимых потоков, которые долго-долго долбят числа или висят в I/O" — т.е. однопоточной программы x N, к параллельному решению относительно маленьких задач, как абстракция "бесконечного количества потоков" становится нежизнеспособной. Все эти "библиотеки и фреймворки" позволяют обойти накладные расходы от ОС путем отказа от этой абстракции; вместо этого создается один или несколько потоков (но не больше количества процессоров!), иногда они еще прибиваются жестко к процессорным ядрам, и все задачи кооперативно выполняются в них.
                                          Интересно, что любой чисто асинхронный код естественным образом порождает задачи, а не потоки; если не ошибаюсь, то, например, все UWP программы такие.

                                            +2
                                            Отлично, все вышеперечисленное как раз подтверждает мою точку зрения. Там где такая архитектура нужна — она УЖЕ есть, и не требует переделки всех систем в мире. Кому-то нужны миллионы микроскопических задач, а кому-то единицы-десятки крупных. Полностью переделывать дизайн ОС из-за этого просто глупо.
                                              0

                                              Да-да, все так и есть. Никто не будет делать новые ОС по другим принципам, раз уже есть старые и привычные. Никто не будет делать новые процессоры по другим принципам, раз уже есть старые и привычные. Пусть неоптимальные, но мы к ним привыкли, кода понаписали… Я уже говорил про обратную совместимость, и вы подтверждаете мою точку зрения ))
                                              На самом деле иногда пытаются — Itanium должен был давать лучший доступ до "настоящего" железа, чем текущие лидеры, Project Singularity пытался избавиться от накладных расходов на изоляцию ядра ОС — увы, они не выжили.

                                          +1
                                          Сколько человеко-лет ушло на написание TBB и всех ему подобных диспетчеров (включая что-то похожее в каждом первом игровом движке)

                                          У меня — пара дней, причём я ещё получил до кучи выигрыш в виде сокращения накладных расходов по сравнению с TBB: универсальные средства не являются оптимальными для каких-то определённых задач.

                                        +2
                                        Вытесняющая многозадачность, раздельные адресные пространства и прочее — это единственный вариант в мире где возможно исполнение недоверенного кода.

                                        Языковые VM тут ничего принципиально не меняют: с точки зрения пользовательского кода, работающего в песочнице, многозадачность всегда будет вытесняющей. Независимо от того кто это самое вытеснение будет обеспечивать — ОС или среда исполнения.
                                          0
                                          Раздельные адресные пространства необязательны (.NET может запускать недоверенный код в общем адресном пространстве).

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

                                          Также, ради оптимизации, jit-компилятор может разбивать цикл по 1e6 итераций на 1e2 циклов по 1e4 итераций и между ними ставить yield, что минимально затронет производительность.
                                            0
                                            1. В каком «общем» адресном пространстве??? Адресное пространство процессов всегда изолировано.
                                            И речь не о том, что общее адресное пространство невозможно, а о том, что оно небезопасно. Поэтому если есть недоверенный код (а он есть всегда), то изоляция адресных пространств обязательна.
                                            2. В чем смысл передачи функций ОС компилятору? И когда появится универсальный компилятор для любого языка?
                                              +2
                                              Разные AppDomains могут находиться в одном процессе и тем не менее, быть изолированными.

                                              В чем смысл передачи функций ОС компилятору?
                                              А в чем смысл идеи VLIW, отдать шедулинг команд компилятору, когда и процессор неплохо справляется. Моё замечание о том, что такая реализация в принципе возможна. Может, с какими-то дополнительными факторами она станет выгодной.
                                                +1
                                                1. Ключевой момент в том, что в одном процессе. Разные процессы обязательно должны быть изолированными.
                                                2. Среди процессоров общего назначения VLIW-разновидностей как-то не очень много. Все-таки это скорее для специализированных процессоров.
                                                В то же время вопрос зачем отдавать scheduling компилятору не лишен смысла и для «обычных» процессоров. «Окно», в пределах которого способен манипулировать исполнением процессор, минимально. В то же время компилятор может делать это в масштабах всей программы, к тому же это снижает сложность, а соответственно, стоимость и энергопотребление процессора.
                                                Но одно дело переносить функции железа на софт, и совсем другое функции софта на тот же софт. Причем ваш вариант однозначно ухудшает результат и вот почему.
                                                В случае с переносом планирования инструкций из процессора в компилятор мы один раз оптимизируем и неограниченное количество раз исполняем уже оптимизированный двоичный код. Миллиарды процессоров экономят при этом буквально гигаватты мощности.
                                                А в случае с переносом вытесняющей многозадачности из ОС, которая исполняет готовый машинный код, в VM, которая исполняет байт-код, мы, наоборот, получаем миллиарды лишних компиляций. И, поскольку такая jit-компиляция должна быть достаточно быстрой, то она, однозначно, будет хуже, чем традиционная aot-компиляция. Т.е. мы будем тратить лишние гигаватты и на саму компиляцию и на хуже оптимизированный код.
                                                И вы не убедите меня, что современные jit-компиляторы очень быстрые и выдают отличный машинный код, пока я наблюдаю ужасные тормоза на многих сайтах, завязанных на js.
                                                  +2
                                                  «Окно», в пределах которого способен манипулировать исполнением процессор, минимально. В то же время компилятор может делать это в масштабах всей программы, к тому же это снижает сложность, а соответственно, стоимость и энергопотребление процессора.

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


                                                  Дело в том, что огромный выигрыш в производительности достигается с помощью динамических оптимизаций предсказателя условных переходов в реальном времени:


                                                  https://stackoverflow.com/questions/11227809/why-is-it-faster-to-process-a-sorted-array-than-an-unsorted-array


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

                                                  Языки с динамической типизацией не могут быть быстрыми.
                                                  И, кстати, тормоза обычно вызваны не интерпретацией JS, а сложностью обработки DOM самим браузером, пересчёта расположения элементов и отрисовкой графики.

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

                                                    Мы его уже получаем.

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

                                                    Предсказание переходов — это не оптимизация кода.
                                                      0
                                                      Вообще-то предсказание переходов — то с чего начинается подавляющее большинство оптимизаций.

                                                      Скажем вынесение констант из цикла, обычно увеличивает работу вне цикла и уменьшает внутри. Чтобы понять — стоит ли овчинка выделки нужно знать сколько раз цикл будет исполняться.

                                                      То же самое — встраивание функций. И далее везде.
                                                        +1
                                                        Начнем с того, что вообще-то динамическое предсказание переходов — это функция процессора, и к компилятору как таковому не имеет ни малейшего отношения.
                                                        Другое дело, что компилятор может организовать код таким образом, чтобы уменьшить количество переходов вообще (как в случае с встраиванием функций) либо сделать переходы более предсказуемыми для аппаратных предсказателей. Но непосредственно «динамическим предсказанием переходов», о чем шла речь в комментарии, на который я отвечал, компилятор, повторюсь, не занимается и заниматься принципиально не может. Я за точность и однозначность терминологии.
                                                          0
                                                          Компилятор занимается статическим предсказанием переходов — например для того, чтобы в более вероятную ветвь условия выполнение «проваливаливалось» (fall through) без перехода.
                                                            –2
                                                            Компилятор не занимается предсказанием переходов. Он занимается генерацией такого кода, который облегчает работу предсказателя переходов в процессоре.
                                                            Даже с точки зрения языка невозможно считать, что кто-то занимается «предсказанием», если этот кто-то «знает».
                                                            Я читал Intel® 64 and IA-32 Architectures Optimization Reference Manual, да.
                                                              +1
                                                              kristerw.blogspot.com/2017/02/branch-prediction.html
                                                              The predictors are defined in predict.def (some of the definitions seem reversed due to how the rules are implemented, e.g. PROB_VERY_LIKELY may mean “very unlikely”, but the comments describing each heuristic are correct). You can see how GCC is estimating the branch probabilities by passing -fdump-tree-profile_estimate to the compiler, which writes a file containing the output from the predictors for each basic block

                                                              Predictions for bb 2
                                                                DS theory heuristics: 1.7%
                                                                combined heuristics: 1.7%
                                                                pointer (on trees) heuristics of edge 2->4: 30.0%
                                                                call heuristics of edge 2->3: 33.0%
                                                                negative return heuristics of edge 2->4: 2.0%
                                                              

                                                              as well as (when using GCC 7.x) the IR annotated with the estimated probabilities.
                                                                0

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

                                                                  0
                                                                  Меня слегка опередил комрад Druu.
                                                                  Именно это я и имел в виду.
                                                                  0
                                                                  Странный спор получается. С одной стороны, вы за то, чтобы упростить процессор за счёт усложнения компиляции. С другой, вы аппелируете к существующему положению дел в современных процессорах, от которых хотите отказаться.
                                                                    0
                                                                    Нет, просто вы слегка упустили контекст.
                                                                    Я лишь говорил, что перенос значительной степени оптимизации в компилятор из железа имеет смысл не только для VLIW (которые мой оппонент привел как пример), но и для более популярных архитектур, таких как x86/x64.
                                                                    Но это было сказано не потому, что я горячий сторонник такого переноса самого по себе, а как пример именно оправданности в противовес неоправданности переноса функций ОС к ВМ.
                                                                    Видимо из-за этого вы и начали со мной спорить, хотя, судя по другим комментариям, вполне разделяете мое мнение о явном преимуществе качества aot-компиляции перед jit-компиляцией, например.
                                                                      0
                                                                      Вполне разделяете мое мнение о явном преимуществе качества aot-компиляции перед jit-компиляцией, например.

                                                                      Конечно. AOT-компиляция позволяет получить более быстрый код, а JIT-компиляция — упростить распространение приложения.


                                                                      И я вообще не рассматриваю архитектуру x86/x64 как удачную. За ней тянется ужасный шлейф обратной совместимости.

                                                                        0
                                                                        Тем не менее на сегодня она обеспечивает максимальную скорость однопоточного приложения. А если приложение портируется на GPU, то все CPU «отдыхают».

                                                                        Потому Top500 и выглядит так, как он выглядит…
                                                                        0
                                                                        По моему этот спор давно разрешил Интел поставляя свой оптимизирующий компилятор. Размер бинарника у него раздувается, но скорость практически всегда выше.
                                                              0
                                                              Мы его уже получаем.

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


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


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


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


                                                              Предсказание переходов — это не оптимизация кода.

                                                              Ничего себе заявление. А profile-guided optimization — это что, по-вашему?

                                                                0
                                                                рограммы придётся распространять не в виде бинарников
                                                                Возможно, маркетинг просто перейдёт от загрузки/поставки носителя к on-demand compilation: пользователь скачивает аналог CPU-Z, отправляет отчёт, платит, скачивает программу, скомпилированную под данную конкретную конфигурацию систему.
                                                                  0

                                                                  Сменил систему — переклмпилируй всё заново.


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

                                                                    +1
                                                                    Сменил систему — перекомпилируй всё заново.
                                                                    И плати повторно, или оплачивай поддержку. Как вариант — дефальтная компиляция, универсальная, но неоптимальная.
                                                                    ещё большие гигаватты электроэнергии будут тратиться
                                                                    Когда это кого останавливало, если отбивается по деньгам?
                                                                      0
                                                                      Дык это… Все ваши предложения уже были реализованы три десятилетия назад.

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

                                                                  Как насчёт «распространять в виде переносимого байт-кода, компилировать в машинный код при первом запуске»? Как-то так делается на Андроиде, емнип.
                                                                    0

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

                                                                      0
                                                                      Она не в реальном времени. После первого запуска сохраняется машкод, для всех последующих запусков он берётся уже готовым.
                                                                        +1
                                                                        То есть пользователь запускает программу, офигевает от тормозов, потому что компиляция не в реальном времени, удаляет. Так, что ли?
                                                                          0
                                                                          Как-то так, да. Ничем не отличается от тормозов при автоапдейте: прогресс-бар и «please wait while we're improving your experience» без указания, сколько времени осталось ждать. К автоапдейтам же вроде все привыкли?
                                                                            0
                                                                            Нет, я не привык.
                                                                            +1
                                                                            В некоторых программах это происходит на этапе установки. За это отвечает модуль docs.microsoft.com/ru-ru/dotnet/framework/tools/ngen-exe-native-image-generator

                                                                            Правда я не часто вижу его использование. Похоже всем плевать…
                                                                          0
                                                                          Как ни странно, в ряде случаев она может быть более эффективной, чем оффлайн-компиляция, поскольку у JIT-компилятора могут быть данные от рантайм-профайлера относительно статистики реального использования кода, что позволит «на лету» подправить машинный код в нужных местах. Но в общем — да, оффлайн качественнее из-за требований к скорости работы JIT.
                                                                        –2
                                                                        И сколько сотых долей процента производительности потеряет программа скомпилированная с другим таймингами?
                                                                        И сколько займет jit-компиляция какого-нибудь «Хрома» или «Офиса»?
                                                                        Ничего себе заявление

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

                                                                          О, мой сокурсник в ИСП РАН над чем-то таким работал. И, насколько я помню, с похожей мотивацией.
                                                                            0
                                                                            Эта идея, прямо скажем, не нова.
                                                                              0
                                                                              Да это понятно, можно даже в P-код-виртуалки не лезть, а вспомнить про всякие дотнеты и JVM. Просто в том случае это было лет 7 назад, и это было именно LLVM именно для плюсов.
                                                                                +1
                                                                                А разве P-код кто-то перекомпилировал? Его интерпретировали или JIT'или вроде.

                                                                                Перекомпиляция — это TIMI, 1988й год…
                                                                        +1
                                                                        Ключевой момент в том, что в одном процессе. Разные процессы обязательно должны быть изолированными.
                                                                        Я потерял мысль, которую вы хотите донести. Мой ответ был возражением на
                                                                        раздельные адресные пространства и прочее — это единственный вариант в мире где возможно исполнение недоверенного кода
                                                                        В качестве контрпримера — vm .net, когда недоверенный код загружается в общее адресное пространство.
                                                                          0
                                                                          Я тоже не совсем понимаю с чем именно вы спорите. Начиная с терминологии. Кроме того вы повторяетесь.
                                                                          В Windows нет никакого «общего адресного пространства», адресное пространство (АП) каждого процесса отделено от АП любого другого процесса.
                                                                          То, что вы можете загрузить недоверенный код внутри АП вашего же процесса неудивительно и естественно. Но получить доступ к АП других процессов (без помощи ОС) вы не можете.
                                                                          И это
                                                                          раздельные адресные пространства и прочее — это единственный вариант в мире где возможно исполнение недоверенного кода
                                                                          вы просто не поняли. Естественно, что можно сделать систему, в которой АП будет общим. С этим никто и не спорит. Только по соображениям безопасности этого делать никто просто не будет. Поэтому, если из контекста для вас неочевидно, то я чуть-чуть переформулирую «раздельные адресные пространства и прочее — это единственный разумный вариант в мире где возможно исполнение недоверенного кода»
                                                                            0
                                                                            это единственный разумный вариант
                                                                            Не слишком ли категорично? Какие фундаментальные проблемы с безопасностью есть у Application Domains в .net?
                                                                              0
                                                                              Речь не о фундаментальных проблемах с безопасностью, а с тем, что Application Domains — это тот же механизм изоляции одной части кода от другой, просто использует не специально предназначенные для этого фичи процессоров, а собственную реализацию.
                                                                              +1
                                                                              Я тоже не совсем понимаю с чем именно вы спорите
                                                                              С тем, что общепринятые способы разделения доступа и ресурсов единственно верные и всегда будут эффективнее.
                                                                          0
                                                                          А в чем смысл идеи VLIW, отдать шедулинг команд компилятору, когда и процессор неплохо справляется.

                                                                          Там смысл в том, что компилятор обрабатывает программу один раз (и может работать хоть час), а процессор — при каждом запуске (и должен делать это очень быстро).
                                                                          При передаче функций ОС компилятору такой мотивации нет.
                                                                            +1
                                                                            Разные AppDomains обладают отдельными кучами и сборщиками мусора, и между ними нельзя передать объект минуя сериализацию с десериализацией. Вполне себе отдельные адресные пространства с точки зрения управляемого кода.
                                                                              +1
                                                                              Логически — да, но для процессора это одно адресное пространство.

                                                                              И тут нет тех накладных расходов на переключения, которые есть у адресных пространств процессов.
                                                                +1

                                                                arteast, согласен. Вы вполне могли бы оформить свои комменты в отдельную статью. Тема то бездонная. Даже если не касаться работы с памятью.

                                                                –1
                                                                Ошибаетесь.) Есть машинный код — он процессору ближе. =)
                                                                +5
                                                                С каких пор язык си низкоуровневый? Тем более общепринято?
                                                                  +5
                                                                  А какой — общепризнано?
                                                                    0
                                                                    Мне попалась на глаза статья Дэвида Чизнэлла, исследователя Кембриджского университета, в которой он оспаривает общепринятое суждение о том, что С — язык низкого уровня, и его аргументы мне показались достаточно интересными.
                                                                      +4

                                                                      Ну, в те годы, когда я учил Си — его называли языком высокого уровня, изредка говоря "среднего" за некоторые низкоуровневые фишки типа адресной арифметики.

                                                                        +4
                                                                        Адресная арифметика даже в некоторых Бейсиках есть. В статье совершенно справедливо упоминается PDP, для которого C был по сути макроассемблером. Для всех других архитектур C ничем не ближе к железу, чем Фортран или Паскаль.
                                                                          +1
                                                                          1. Так я и говорю — не называли его языком низкого уровня.
                                                                          2. Кроме PDP-11 было ещё много архитектур, на которые C ложился «достаточно прямо». В том же 8086 была сломана только адресация (сегмент-смещение, нигде больше не видел подобного ада), но она была сломана для всех языков. Зато были базовые регистры, в частности регистр BP, в который копировался SP — т.е. нормальная поддержка стек фреймов, что очень ценно для наивной реализации компилятора Си. И никакого предсказания переходов.
                                                                          Или hitachi sh3 — на котором я впервые увидел, как компилятор Си выдаёт предельно оптимизированный код. С delayed branches вместо предсказания переходов — гениальное решение.

                                                                          P.S. И ведь статья-то на итог вообще не об этом, и гораздо интереснее темы из заголовка…
                                                                      +6
                                                                      There is no official definition, but historically assembler/machine code was considered low-level and any language more abstracted was high-level. But C is one of the high-level languages which is closest to the machine level, which is why it is sometimes designated «mid-level», while scripting languages like Python have sometimes been designated «very high level». But these are all informal categories and somewhat subjective.
                                                                      ++ www.quora.com/Why-is-C-considered-a-low-level-language
                                                                        +1
                                                                        Вас еще кто-то минусует. Тоже удивлен существованию дискуссии о высокоуровневости Си.
                                                                          0

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

                                                                            0
                                                                            По всей видимости, те, кто называет Си низкоуровневым подразумевают некоторый неформальный контекст.
                                                                        +2
                                                                        Всё-таки ARM SVE — это *Scalable* Vector Extension, а не Scalar.
                                                                          +6
                                                                          Чего только на волне хайпа с этими практически умозрительными багами не напишут. И С уже стал резко высокоуровневым, и замедление от патчей отбросило перформанс на годы назад, аяй…
                                                                          Не можете понять как компилируется ваш С-шный код? Включите трансляцию в ассемблер и читайте. Придется правда в C ABI разобраться, но то такое.
                                                                          Не нравится что компилятор слишком умный? Поставьте -О0 и вперед — оптимизируйте руками.

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

                                                                          >>Эта информация в C гораздо более ограниченна, чем в таком языке, как Fortran, что является основной причиной того, что C не сумел вытеснить его из сферы высокопроизводительных вычислений.
                                                                          Фига с два. Основной причиной является то, что на фортране дочерта и больше Legacy кода, который тянется с мохнатых 80-х или 70-х, в том что в тех же годах математики и физики очень привыкли фигачить все на фортране. Практически до 2000-х, когда видимо начинать новый проект на фортране стало уж совсем моветон. Реализация С-шных и С++ вещей на фортране часто вызывает улыбки. Например чтобы преобразовать 2-д в 1-д массив без вызова решейпа (затратной операции, которая реально перекладывает данные) — фиганем его через функцию, в которой массив определим «как придет» — потеряем дескриптор, но зато можем заюзать его как угодно. Или реализация полиморфных объектов через интерфейсы…
                                                                          Короче не от хорошей жизни там извращаются.
                                                                            +2
                                                                            Не понимаю, чего все привязались к названию статьи? Понятно, что это действительно не совсем корректное заявление.
                                                                            Мне кажется, что главный посыл автора не в том, что все сишники на самом деле джависты (не в обиду последним), а в том, что возможности современного железа очень сильно упираются в сишное представление вычислительной системы. Поэтому автор предлагает взглянуть на мир под другим углом. Мне вот понравились мысли про кеш — хоть я еще не залезал в его когерентность, я слышал, что там все плохо, и возможно то, что предлагает автор, действительно улучшило бы ситуацию. Но, как уже писали выше, легаси есть легаси…
                                                                            С другой стороны, про параллельные системы я не согласен. Видеокарты, которые так восхваляет автор, хороши в своих задачах, но если попробовать реализовать на них какую-то бизнес-логику, то, мне кажется, получится что-то страшное и непонятное, и оно будет медленнее, чем простой C на обычном процессоре.

                                                                            P. S. Про Фортран — полностью с Вами согласен.
                                                                              +3
                                                                              Не можете понять как компилируется ваш С-шный код? Включите трансляцию в ассемблер и читайте. Придется правда в C ABI разобраться, но то такое.

                                                                              А если не можем понять, как (и сколько времени) выполняется наш ассемблерный код, потому что внутри процессора он транслируется в нечто недокументированное, тогда что читать? :-Р
                                                                                –5
                                                                                Документацию на процессор. В конце мануала вы найдете таблицу со всеми коммандами, у которых указан Latency и Throughput.
                                                                                  +4
                                                                                  Дык статья ровно о том, что последний процессор, для которого был такой мануал — это 80486. Появился в 1989м, не выпускается с 2007го.

                                                                                  А если вы про эту — так она не из мануала, а из экспериментов и, кроме того, в ней масса ньюансов не описана.
                                                                                    +2
                                                                                    Всегда значит был, а тут вдруг не стало.
                                                                                    Я не припомню процессора для которого не было таблицы с латентностями-трупутами, а занимаюсь я оптимизацией ПО уже более 10 лет.
                                                                                    Вот вам по скайлейку несуществующая табличка от производителя:
                                                                                    software.intel.com/sites/default/files/managed/ad/dc/Intel-Xeon-Scalable-Processor-throughput-latency.pdf
                                                                                      +6
                                                                                      В вашей табличке даже не написано на каких блоках какие команды можно исполнять впараллель. А это — очевидно необходимое (но не достаточное!) требование для ответа на вопрос «как (и сколько времени) выполняется наш ассемблерный код»!

                                                                                      Все эти описания, увы, это не чёткое, точное и жёсткое описание, как для 8086 или 80486, а, скорее, некоторые эвристики, позволяющие с некоторой точностью сравнивать куски ассемблерного кода. Для окончательной оценки — всё равно нужно запускать на железе и мерить. Ибо… «возможны варианты».
                                                                                        0
                                                                                        Я, видимо, несколько потерял нить беседы. Зачем вам знать «как (и сколько времени) выполняется наш ассемблерный код» с точностью до такта? Особенно с учетом того, что реальный код все равно взаимодействует с памятью, скорость которой заранее неизвестна, а, следовательно, с иерархией кэшей.
                                                                                        +1

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

                                                                                    0

                                                                                    Тогда нужно устраиваться в компанию разработчик процессора и читать внутреннюю документацию. Или сломать их систему и достать доки нелегально. Или реверснуть логику процессора. Какой вариант вам больше нравится? =)

                                                                                  +3
                                                                                  Могу судить по сфере встроенного ПО для микроконтроллеров разных архитектур.

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

                                                                                  Проще говоря, программист на С и программист на машинных кодах выдадут исполняемый бинарник с совершенно минимальными отличиями.
                                                                                  Куда же низкоуровневее?
                                                                                    +2
                                                                                    Да как бы, уже очень давно сами по себе х86 инструкции для процов — это такой же байткод как и Java и .Net
                                                                                      +2
                                                                                      Я намеренно указал, что архитектуры не ограничиваются x86
                                                                                        0
                                                                                        Ну так в статье как раз наоборот, для архитектур есть ограничения. Так то понятно, что при желании можно найти проц который будет простой машиной Тьюринга.
                                                                                          +5

                                                                                          Нельзя, у машины Тьюринга бесконечная лента.

                                                                                        –2
                                                                                        Байт-код Java это язык низкого уровня, а ЯП Java это язык высокого уровня.
                                                                                        0
                                                                                        Куда же низкоуровневее?
                                                                                        Так вы же сами и ответили:
                                                                                        Самое низкоуровневое, что доступно программисту — это машинные коды. Машинные коды можно хоть по бумажной таблице перевести в ассемблер (и обратно) даже вручную.
                                                                                          0
                                                                                          Есть еще микрокод процессора.
                                                                                            0
                                                                                            Он же не доступен для программиста, поэтому, думаю, рассматривать его в качестве ЯП не очень корректно.
                                                                                              –1
                                                                                              Думаешь, на нем офисные работники пишут, а не программисты? =)

                                                                                              Вполне реальная идея, чтобы компилятор генерил микрокод (мне даже кажется, что LLVM затачивался в т.ч под это). Но по ряду каких то причин (я бы предположил ноухау/патенты, невозможность разделения ответственности итп), этого делать не дают.
                                                                                                +1
                                                                                                На нем пишут разработчики конкретного ЦПУ в процессе его создания, это совершенно не то же самое. Т.е. микрокод является его неотъемлемой частью и рассматривать его как язык способный программировать ЦПУ в целом — это уже какой-то уроборос получается
                                                                                                  –1
                                                                                                  Нет уробороса. Ниже уже электросхемотехника, так что все — .
                                                                                                    +1

                                                                                                    Микрокод это неотъемлемая часть конкретного ЦПУ, меняя микрокод вы меняете ЦПУ а не программируете его.

                                                                                                      0

                                                                                                      Микрокод не является неотъемлемой частью процессора, потому что относительно легко заменяется. (Без физических манипуляций).


                                                                                                      WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
                                                                                                      
                                                                                                      amd64-microcode/bionic-updates,now 3.20180524.1~ubuntu0.18.04.2 amd64 [installed,automatic]
                                                                                                      intel-microcode/bionic-updates,now 3.20180425.1~ubuntu0.18.04.2 amd64 [installed,automatic]
                                                                                                      microcode.ctl/bionic 1.18~0+nmu2 amd64
                                                                                                        +2
                                                                                                        Легкость замены части чего-то не отменяет принадлежности этой части к целому. Вы можете относительно легко поменять колеса на автомобиле и это изменит характер его движения, но меняя колеса вы не управляете автомобилем в смысле езды.
                                                                                                          0
                                                                                                          Хотя, конечно, обновляемый микрокод смазывает границы, но все же наличие микрокода не делает машинный код высокоуровневым языком.
                                                                                                  0
                                                                                                  Это очень старая идея. Когда-то мой отец занимался тематикой трансляции Фортрана в микрокод, еще в советское время.

                                                                                                  Один чешский деятель, сейчас не вспомню университета и регалий, реализовал это году в 2008 — трансляция С в микрокод (не помню, какой именно, не суть).

                                                                                                  Моя дипломная работа посвящена в чем-то аналогичной идее — доступу напрямую к микрокоду.
                                                                                                    +1

                                                                                                    Вы имеете ввиду VLIW?


                                                                                                    https://ru.m.wikipedia.org/wiki/VLIW

                                                                                                    0
                                                                                                    Почему недоступен?
                                                                                                    Зависит от процессора и от программиста.
                                                                                                      0
                                                                                                      Я только могу еще раз повторить то же, что отвечал чуть выше Siemargl'у.
                                                                                                +1
                                                                                                Раз уж там упоминался SPARC.
                                                                                                Весной к нам в контору приезжали представители МЦСТ и рекламировали помимо своих VLIW Эльбрусов свой же компилятор С.
                                                                                                Так вот судя по их словам, обогнать себя самого на VLIW-ассемблере либо нельзя, либо на считанные проценты, относительно того же грамотно написанного С-кода в связке с оптимизирующим компилятором.
                                                                                                Так что будь то ARM, SPARC или что-либо ещё — суть не меняется.
                                                                                                Ниже машинных кодов ни в одной архитектуре не опустишься. И С даёт результат чрезвычайно близкий к вручную написанным машинным кодам.
                                                                                                  0
                                                                                                  Ниже машинных кодов ни в одной архитектуре не опустишься.

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

                                                                                                  Но это не точно. (с) По крайней мере в тех кусках, с которыми я ковыряюсь на предмет оптимизации на asm-е.
                                                                                                    0
                                                                                                    Именно поэтому я и написал про 90%. В тех редких случаях, когда компилятор всё-таки так и не догадался, как именно можно было срезать углы. И это вопрос качества С-кода и качества компилятора.
                                                                                                      –3
                                                                                                      Существенно менее 90%.
                                                                                                      Ложь скрывается в том, что это только для программ написанных квалифицированными программистами, знающими архитектуру для которой пишут, как минимум на уровне ассемблера. Код скопированный со «стековерфлоу» без «творческой» обработки на 100%, или из-за не знания алгоритмов, или неадекватности алгоритма под конкретную архитектуру (где важны учет операций пересылки, ветвления, а не количества арифметики или количества сравнений, и прочая, и прочая...).
                                                                                                      Ложь заключается в том, что си низкоуровневый только в том, что он не предоставляет инструментария, доступного в языках высокого уровня: он не дает никаких гарантий; код на ассемблере или блисе, чуть более низкоуровневый, только потому, что там работа с типом еще менее ограниченна (есть, но никто, ничего гарантировать не может!).
                                                                                                      Языки низкого уровня — это языки которые выбирают ССЗБ, разменивая простоту и ограничения абстрактных машин ( DSL[language] -языков ) на максимальную доступность функциональности архитектуры на текущих ЦПУ, минимизируя ответственность за качество кода, выразительность, обозримость, управляемость коллективной разработки (всем все доступно, можно трюкачить, зная «что внутри»; как результат было больше ограничений встроено в си++, java… языках высокого уровня и ООП, с их инкапсуляцией… правда с тех пор мы потеряли Пакеты Прикладных Программ(этакий сорт библиотек, которые мы тоже потеряли)… ССЗБ).
                                                                                                      Язык — это всегда! система ограничений [как и языки человеческого общения], я говорю не только о синтаксисе/семантике (да, и они входят в эту систему), но о том, что эта система строится для удобства получения конкретного! результата, через высокоуровневую систему типов (функциональность, в си реализовано только покрытие модальных целых, реализованных в ЦПУ, даже с float/double принято решение в пользу усеченных, в сравнении с фортрановскими или ди, SIMD — чисто архитектурные, а матрицы реализованы только в языках-матпакетах, работа с временем, цветом, видео… скоро (видимо) будет только через #nodejs, на amazon cloud, а пользователю будет отсылаться только картинка со звуком, получая управленческие импульсы прямо из мозга человека-обезьянистого [сарказм] ). Си — это язык unix, как было задумано, использование его иначе чревато овердрайвом, OS обязаны (теперь!) предоставлять всю (открытую) функциональность операционки из конца 60х, ее безответственность по отношению к пользователям, требуя высокой квалификации и обоймы программ накладывающих ограничения на это пиршество свобод…
                                                                                                      Конечно, идеалом не является программа с единственной кнопкой «сделай мне хорошо», но язык не определяется свободами, язык — это средство общения, как идеал, си не подходит более чем полностью, он не может даль ничего более (в сравнении с ассемблерами, тем более с макро-… или тем же occam-2, а тем более с ada или c++). Единственное, что дает си — это качественные (на текущий момент) оптимизирующие компиляторы, и легаси, накопившееся с доисторических времен, когда компьютеры были большими.
                                                                                                    0
                                                                                                    Так вот судя по их словам, обогнать себя самого на VLIW-ассемблере либо нельзя, либо на считанные проценты, относительно того же грамотно написанного С-кода в связке с оптимизирующим компилятором.


                                                                                                    А самое интересное еще впереди — интернет-гиганты пытаются применять машинное обучение к построению hardware. То же самое происходит и по направлению к компиляторам. К сожалению, быстрое гугление пока не дало результатов. На мой взгляд, стоит ждать скорого сокращения разрыва между лучшими оптимизаторами в лице человека и оптимизаторами компилятора.
                                                                                                    +7

                                                                                                    В своё время нам так разъясняли, чем отличаются языки высокогоуровня от низкого — наличием абстракции. По скольку типы данных и операции языка С абстрагированы от архитектуры — он является языком высокого уровня по определению. Например, такие вещи, как операции с плавающей точкой, являются частью стандарта языка С, однако некоторые архитектуры имеют только целочисленные АЛУ, но благодаря компилятору, программисту не надо об этом заботиться. Разработчики, использующие языки с бОльшим уровнем абстракции, как GO, например, считают С языком низкого уровня, но это не так.

                                                                                                      +2
                                                                                                      Всё относительно. В машинном коде это один и тот же регистр EAX в двух командах, а при выполнении это будут разные регистры из-за переименования регистров, например. В машинном коде мы пишем значение по адресу памяти, а в процессоре при этом обновляются различные кеши, отсылаются определённые сообщения по внутрипроцессорной шине другим ядрам, чтобы синхронизировать их кеши при необходимости, то бишь налицо высокоуровневая операция над низкоуровневыми примитивами. И наверняка есть какой-нибудь отладочный режим, в котором все эти низкоуровневые операции доступны для прямого программирования и наверняка достаточно умный программист (или компилятор) смог бы выжать больше процентов производительности в конкретной программе при наличии доступа к этим низкоуровневым примитивам.
                                                                                                        –4

                                                                                                        Не нужно путать мнемокод ассемблера и машинный код. Машинный код это двоичные данные, которые непсредственно исполняет процессор, и ничего там уже не переименовывается и не изменяется. Есть ещё байт-код, например Java, но он исполняется не непосредственно процессором, а run-time интерпретатором — специальной программой, которая превращает байты этого кода в вызовы специальных подпрграмм — он так же не является машинным кодом!
                                                                                                        Если Вы на assembler напишете программу, то каждая инструкция будет однозначно преобразована в машинный код, и если дезассемблировать полученный дамп данных, вы получите практически тот же исходный код, единственное — это символические имена меток и адресов памяти будут в виде цифр. Поэтому assembler и является языком низкого уровня. Вам нужно знать все спецификации процессора, для которого пишетсчя программа — никакой абстракции, bare metal!
                                                                                                        Чтобы пояснить наглядно разницу низкоуровневого ассемблера и высокоуровнего С, приведу маленький пример из жизни 8-битных микропроцессоров AVR. В серии megaAVR есть блок умножения и соответствующая инструкция mul, а в tinyAVR такого блока и инструкции — нет. То есть, написанная программа на ассемблере, для megaAVR с использованием инструкций mul не может быть скомпиллирована для tinyAVR. Все операции умножения прийдется заменить подпрограммой умножения, которая использует, допустим, сложение в цикле. Это говорит о том, что программист должен знать сиецификацию целевого процессора, набор команд, регистров итд. В С можно просто написать a=b*c; и это без переделок можно скомпиллировать для любого процессора, даже не задумываясь, может ли его АЛУ перемножать числа или нет. Компилятор языка С сам заменит умножение на нужрую инструкцию или подпрограмму, в зависимости от используемого целевого процессора.

                                                                                                          +9
                                                                                                          Машинный код это двоичные данные, которые непсредственно исполняет процессор

                                                                                                          Для x86 это и близко не так. Собственно, про это и статья.

                                                                                                            +4
                                                                                                            Машинный код это двоичные данные, которые непсредственно исполняет процессор, и ничего там уже не переименовывается и не изменяется.
                                                                                                            На календарь смотрели? Последний x86 процессор, где ничего не переименовывалось и не изменялось (хотя кеши были уже и там) — это Pentium! Вышедший четверть века назад!

                                                                                                            И для ARM-процессоров — это тоже уже не так (про Denver почитайте, что ли).

                                                                                                            Да, в embedded это ещё временами так, ну так в статье не про это речь…
                                                                                                              –1
                                                                                                              Процессор не исполняет данные. Он из машинного кода берёт адреса инструкций и данных. Суперскалярные процессоры исполняют код магическим (для программиста) образом, совершая несколько переходов в конечном автомате программы одновременно.
                                                                                                          0
                                                                                                          ----а делали быстрые процессоры с интерфейсом PDP-11.

                                                                                                          Мне кажется автор имеет весьма смутное понимание о машинах PDP-11.

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

                                                                                                          Интел тут со 180 коммандами в паралель выглядит бледно.

                                                                                                          Слово эмуляция, мне кажется, неуместно.
                                                                                                            0
                                                                                                            Да, точно подмечено. У PDP-11 не было ни суперскалярности, ни предсказаний, ничего, что привело к появлению спекулятивных уязвимостей. Ортогональная система команд, один из лучших ассемблеров, который я видел. До сих пор помню часть memcpy :)
                                                                                                            mov @(r0)+, @(r1)+
                                                                                                            –1
                                                                                                            VLIW Эльбрус основан на архитектуре E2K, а не SPARC.

                                                                                                            И С даёт результат чрезвычайно близкий к вручную написанным машинным кодам.

                                                                                                            Вы не читали статью. Современные компиляторы делают массу трансформаций, в т.ч. выворачивают циклы наружу и меняют порядок операций. Т.е. получается код и близко не похожий на то что вы написали.
                                                                                                              +1
                                                                                                              Вы не читали мой комментарий.
                                                                                                              Современные компиляторы выдают машинный код практически идентичный по качеству тому машинному коду, который я могу написать вручную, зная все особенности данной архитектуры.
                                                                                                              Я нигде не говорил, что С-код впрямую транслируется в машинные коды. Я говорил о том, что компилятор выдаёт машинный код, который мне очень сложно обогнать, решая ту же задачу на ассемблере (или в машинных кодах). Мой машинный код получится на 90% идентичный тому, что сгенерировал компилятор.

                                                                                                              А Эльбрус — это ещё и R-серия, которая чистый SPARC.
                                                                                                                0
                                                                                                                практически идентичный по качеству тому машинному коду, который я могу написать вручную, зная все особенности данной архитектуры.

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


                                                                                                                Что же до "90% идентичный", то компиль обладает замечательной возможностью перемешивания инструкций на конвейере, что позволяет выполнять код быстрее его прямолинейного составления и в итоге он должен стать даже быстрее того, что пишет человек

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

                                                                                                                С тех пор было создано огромное множество языков, и все они — одинаково высокоуровные согласно этой классификации. C, C++, C#, JavaScript, Python, да даже LLVM — всё это высокоуровневые языки. В этом случае подобная классификация не имеет никакого смысла.

                                                                                                                То есть имеет смысл в относительной классификации, а не в абсолютной, или в нескольких уровнях градации высокоуровневых языков:
                                                                                                                — абстрагирование от работы с регистрами и машинным представлением данных (C­);
                                                                                                                — наличие структур данных: объектов, функций высших порядков (C++)
                                                                                                                — абстрагирование от прямой работы с памятью (.NET, JVM);
                                                                                                                — абстрагирование от операционной системы (JavaScript).
                                                                                                                  +1
                                                                                                                  Если javascript решает задачу абстрагирование от операционной системы — то он её ниразу не решил.
                                                                                                                    +2

                                                                                                                    Как минимум один раз решил — моё приложение одинаково работает на айфоне, андроиде, в файрфоксе на убунту, в сафари на маке и хроме на винде.
                                                                                                                    Так что ваше заявление ложно.

                                                                                                                      +1
                                                                                                                      Да-да, моя Qt программа тоже без проблем собирается на винде и убунту, но есть нюансы

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

                                                                                                                      Для бинариков тоже есть разные приблуды. Вроде WINE, которые симулируют x86 и x64 окружение Windows, сохраняя весьма приличную производительность. Или обратную фишку для POSIX от мелкософта. Всё вроде работает, но нет совместимости баг-в-баг.

                                                                                                                      Для жабоскрипта ОС — это среда выполнения, обычно, браузер. Внезапно в хроме, огнелисе, сафари и эдже есть куча собственных костылей, которые нужно учитывать, а ведь есть ещё node и другие ребята. Дабы далеко не ходить, как давно в них во всех появилось общее имя для корневого элемента? У вас одинаково — или у меня вся вёрстка рассыпется на левом браузере с кастомной темой? Да ладно, у меня в Вивальди или, ть, Амиго точно всё работать будет?
                                                                                                                        +1
                                                                                                                        Да ладно, у меня в Вивальди или, ть, Амиго точно всё работать будет?
                                                                                                                        А что это за операционные системы такие? Я таких не знаю.

                                                                                                                        Зависимости от операционной системы таки больше нет. А от браузера — да, таки есть. Что вас удивляет?
                                                                                                                          0
                                                                                                                          А что это за операционные системы такие? Я таких не знаю.
                                                                                                                          Я надеюсь, это сарказм. А так, нет, не удивляет — забавляет. Люди говорят об избавлении от зависимостей, а потом пишут многотомные проверки на версии браузеров и поддержку фич. Нуок, «везде всё одинаково», «вёрстка почти не поехала».
                                                                                                                            +3
                                                                                                                            Люди говорят об избавлении от зависимостей, а потом пишут многотомные проверки на версии браузеров и поддержку фич.
                                                                                                                            Увы, избавиться от зависимости нельзя, если ты хочешь общаться с реальным миром. Можно только передвинуть их. JS успешно заменяет зависимость от операционки на зависимость от браузера. Это всё равно большой шаг вперёд, так как, к примеру, на мобильнких и PC есть одинаковые браузеры, а одинаковых операционок — нету.
                                                                                                                          0
                                                                                                                          Для точекнету и жабомашины ОС — виртуальная машина.

                                                                                                                          Но и там, и там есть возможность взаимодействия с нативным кодом, возможность вывоза функций системы и взаимодействие с её сущностями.


                                                                                                                          А в JavaScript и этого нет, взаимодействие идёт только с браузером.


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

                                                                                                                          Если бы существовала серебряная пуля, было бы легче, правда?

                                                                                                                            0
                                                                                                                            Пиши на ES5, не используй самые новые браузернозависимые фичи, и скорей всего никогда* не столкнёшься с костылями под разные браузеры, не говоря уж о ОС.

                                                                                                                            *Hе касается Вивальди.
                                                                                                                        0
                                                                                                                        С тех пор было создано огромное множество языков

                                                                                                                        Но и классификация языков не стояла на месте. Все перечисленные вами языки вполне классифицируются без необходимости введения нового способа классификации.
                                                                                                                          +1
                                                                                                                          .NET и JVM тоже абстрагированы от операционных систем, во всяком случае десктопных.
                                                                                                                            +1
                                                                                                                            Да, поэтому такие уродские иконки в трее и окно сохранения файлов.
                                                                                                                            Или всеми любимый COM или ADO драйвера не той разрядности.
                                                                                                                            В общем не обобщайте. На серверах все немного проще.
                                                                                                                          +4
                                                                                                                          1. Вообще не понятно причет тут язык в частности C. Это проблемы другого плана.
                                                                                                                            Современные программы тормозят совсем по другим причинам. Компилятор тут вообще не причем. Главная причина экономическая. Надо получать прибыль быстро, поэтому разработчики имеют топовое железо, что бы быстрее выкатить хоть как-то рабочую версию. У них работает приемлемо и ладно. То что у пользователя тормозит — это проблемы негров. Пусть покупают новое железо. Взгляните на java — академически правильный язык, быстрый, хорошо структурированный автоматически следит за память… всё шикарно. Но программы на java приобрели славу тормозного, жрущего ресурсы по. Почему да потому что там тысячи абстракций, куча библиотек обёрнутых в другие библиотеки да еще всё это разных версий.
                                                                                                                            Если старый word 2003 запустить на новой машине. Всё работает просто мгновенно по стравнению с word 2016, хотя решают они одинаковые задачи набор и печать текста и компиляторы стали лучше и делают массу трансформаций, и операционка новее и ядер больше. Но когда курсором мигают через javascript это всё коту подхвост
                                                                                                                          2. Паралельный код писать очень сложно и поддерживать дорого. Особенно на языках к жтому не приспособленных. А использовать всю вычислительную мощность конкретной системы иногда вообще невозможно. Плюс массивно паралельных систем сейчас очень много видов. Поэтому приходится использовать абстракции openmpi,opencl,openal,… и готовые готовые библиотеки IPP, gpu-accelerated-libraries… Более того некоторые алгоритмы не имеют общих рецептов распараллеливания.
                                                                                                                          3. В модель акторов не панацея она создаёт больше проблем чем решает.
                                                                                                                          4. Высокоуровневый язык это sql вы ему пишете что хотите, а он уже сам строит план выполнения, выполняет и возвращает вам результаты.
                                                                                                                          5. Язык C полный по тюрингу и на нём теоритически можно написать что угодно. C компилятор есть почти под любую платформу. Если нет то его просто написать, т.к. сам язык простой.
                                                                                                                          6. Сам язык прост в изучении. Главное отличие C от C++. C необходим для написания маленьких утилит которые потом объеденяются в рабочую систему языками склейки (bash,python,lua,java...). C в отличии от C++ имеет вменяемый бинарный интерфейс. С другой стороны C++ претендует на то чтобы писать огромные «титаники» в которых весь функционал пихают в одну программу.
                                                                                                                          7. Постоянное развитие C++ ведёт его в сторону усложнения, как для изучения так и для написания компиляторов. И к сужению количества платформ под которые можно компилировать. При этом не решая практических задач. (например php из коробки умеет общаться с базами данных, работать с архивами и т.п.)
                                                                                                                          8. Более того не всегда ясно какое наречие языка C++ надо использовать, что бы не огрести проблем.
                                                                                                                          9. Для решения задач распараллеливания есть экспериментальные языки типа halide-lang.org которые пытаются дать инструмент для анализа и поиска компромисса локальности, параллельности и порядка вычислений.

                                                                                                                          ps: Главная нерешенная задача в программировании это борьба со сложностью.
                                                                                                                            +3
                                                                                                                            Высокоуровневый язык это sql вы ему пишете что хотите, а он уже сам строит план выполнения, выполняет и возвращает вам результаты.

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

                                                                                                                              +1
                                                                                                                              1.1. Я эту старую песню о главном слышу с 2003 года. «Процессоры стали сильно мощные, их нужно замедлять искусственно, чтобы покупали новые.» Это очень красивые слова, которые нужно доказать метриками. А ещё лучше, разбором топологии. А с этим будет очень непросто. А пока это не сделано, к подобным фразам можно относиться так же, как к вою о вреде ГМО.
                                                                                                                              1.2. Очень красивый пример с вордом. Но давайте ближе к нашим тушкам. Давайте сравним студию 2003 и 2017. Начните с тормозной новой, а потом перейдите на быстролётную старую. Только попытайтесь не блевать в процессе.
                                                                                                                              2. Да и нет. MPI и прочие — они не про параллельность выполнения операций. Они о командной работе. Про параллельность — OpenMP. ИМХО, там достаточный набор команд для нормального распараллеливания задачи. Если вам нужно больше — вы пытаетесь решать несколько задач одновременно.

                                                                                                                              Остальные пункты вообще непонятно о чём. Вы не расчёсывайте плюсы — они и чесаться у вас не будут.

                                                                                                                              Настоящая проблема в том, что разработчики процессоров не дают программистам прямого доступа к управлению процессором. Да что там, даже косвенного не дают. Понятное дело, безопасность, все дела… Но в чём проблема добавить определение расположения переменной в памяти на уровне прагм и деклараторов?
                                                                                                                              int __declspec(allocate(L3Cache)) bigRoutineCounter; 

                                                                                                                              Но нам, почему-то, не доверяют делать вот такие советы. Вот это, на самом деле, печально и обидно.
                                                                                                                                0
                                                                                                                                Проблема не в языках, а в тех, кто на них пишет. Разработчики процессоров фактически тоже не при делах. Современные разработчики серьезно игнорируют проблемы оптимизации своего кода в пользу скорости и удобства разработки. Компилятор все за всех не заоптимизирует. В случае интерпретируемых языков — все еще хуже.
                                                                                                                                  0
                                                                                                                                  Говнокодеров в процентном отношении за последние 30 лет сильно больше не стало. Просто раньше не было гитхаба и перестека, поэтому насладиться кодом надмозгов было куда сложнее, как и плодами их трудов — ибо чаще всего они не могли выбраться за пределы их собственной пеки.

                                                                                                                                  К тому же, что это за аргументация? Это ж бред! Как минимум, разработчики компиляторов, игр и высоконагруженных систем кровно заинтересованы в каждой доле процента производительности. Если размещение простых ничего не обязывающих прагм работы с кешем позволит повысить производительность на 1% — это уже серьёзно. Если дать возможность программисту задавать вероятности выполнения условий — и передавать их прямо в процессор, можно ожидать огромный скачок производительности всего кода, особенно, JIT.

                                                                                                                                  Пускай это будет расширение Intel или AMD. Пусть это будут «рекомендации» типа inline. Пускай 99% кладут на оптимизацию. У оставшегося процента программы будут значительно быстрее, а зарплаты — выше. И это прекрасно, даже если меня в этом проценте нет и не будет.
                                                                                                                                  +1
                                                                                                                                  > Давайте сравним студию 2003 и 2017

                                                                                                                                  Кстати предпочитаю использовать Visual Studio 2005, а не 2017 (там где требуется старый уровень С++). Заметно быстрее работает и все что надо в основном есть (отладка, редактирование, навигация). Там где можно использовать новый С++, там понятно лучше новая студия (ибо старая перестает работать как IDE), но каких-то особых плюсов я не вижу (кроме «Rename» — может чего не нашел?), а минусы в виде пониженной производительности и повышенного потребления ресурсов я замечаю.
                                                                                                                                    0
                                                                                                                                    Давайте немного отвлечёмся от плюсов, так как MS явно не горит пламенной любовью к крестовикам и поддерживает их сравнительно бедно. Сравните редактор C#. Сравните подсветку и автодополнение, построение схем кода и тп. Они разительно отличаются. Тот же IntelliSense превратился из «о, боже мой, как это отключить» во вполне себе полезный инструмент, которого вполне хватает. И так во всём.

                                                                                                                                    Нет, меня самого радует сверхотзывчивая среда разработки. Но меня так же радует комфорт. Если отключить все подсветки и украшательства, окажется, что новая студия быстрее старой и может оперировать бОльшими файлами. Вот только зачем нам нужен очередной блокнот?
                                                                                                                                    +2
                                                                                                                                    1.2. Очень красивый пример с вордом. Но давайте ближе к нашим тушкам. Давайте сравним студию 2003 и 2017. Начните с тормозной новой, а потом перейдите на быстролётную старую. Только попытайтесь не блевать в процессе.
                                                                                                                                    Блевать может захотеться от ограничений старых версий компилятора, но вот UI у старой версии — таки приятнее и удобнее.

                                                                                                                                      +1
                                                                                                                                      Я эту старую песню о главном слышу с 2003 года. «Процессоры стали сильно мощные, их нужно замедлять искусственно, чтобы покупали новые.» Это очень красивые слова, которые нужно доказать метриками.

                                                                                                                                      Я пишу софт на Паскале для большого зоопарка систем от первых Селеронов и Атлонов (даже без SSE) до современных 18-ядерных. Который должен работать годами без остановки. И так получается, что если отвязать логику от гуя и от ввода-вывода (через очереди команд), то многое можно сделать асинхронным и легко распараллелить. И тогда проблем с быстродействием процессора практически не возникает, все начинает упираться в диск, сеть и память. И разница между системами 15-летней давности и современными оказывается не столь велика — везде есть какие-то узкие места, то в рейд-контроллере через неделю работы деградирует кеширование запись, то запись в SSD деградирует, то вдруг ОС решит дисками пошуршать по своим делам, то память фрагментируется до неприличия, не может найти непрерывный кусок в десяток мегабайт при свободном десятке гигабайт… А у процессора на самом деле моща гигантская, сотни миллионов операций в секунду. И эта моща может легко уйти в свисток в каком-нибудь банальном цикле поиска или сравнения строк, выполняемого для каждой ячейки таблицы. Для которых есть специальные команды процессора, но компилятор и библиотеки языка программирования решили, что для уникода это не годится.
                                                                                                                                        +2
                                                                                                                                        Пардон пур мон франсе, а разве паскаль ещё жив? Последний стандарт был в прошлом веке. Быть может, вы о делфи? Но и с ним всё не так хорошо. Насколько я знаю, он последние лет 6 мучительно агонизирует. Тем более, ни первый, ни второй никогда не претендовали на поразительную скорость и близость к железу. Так чего ждать от старых компиляторов?

                                                                                                                                        И, вы серьёзно? То, что вы описываете — отсутствие гигиены, причём, принудительное. Та же дефрагментация по умолчанию выполняется по расписанию еженедельно. Если перестать убирать пыль, любой ПК вышедший после 1996 года рано или поздно вызовет пожар. То же в ОС. У меня на моих задачах даже между Core2Duo 2008 года и Athlon2x4 2011 года разница ощущается весомая. Если вы i9 увайдохиваете в днище… Остаётся только снять шляпу перед вашим мастерством!
                                                                                                                                          0
                                                                                                                                          И, вы серьёзно? То, что вы описываете — отсутствие гигиены, причём, принудительное. Та же дефрагментация по умолчанию выполняется по расписанию еженедельно.

                                                                                                                                          Как дефрагментировать память в Windows без перезапуска приложения? =)

                                                                                                                                          На процессоре i3 обычно нагрузка 1-3%, на старых 10-20%. Там просто данные из разных портов обрабатываются и отправляются в сеть + кладутся на диск в виде логов и БД. Но данных много, в сутки до 2 Гб логов.
                                                                                                                                            +2
                                                                                                                                            Как дефрагментировать память в Windows без перезапуска приложения? =)

                                                                                                                                            Смотря как приложение написано и как оно работает с памятью. Любой compactifying GC именно что дефрагментацией и занимается как побочный эффект.

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

                                                                                                                                            Но данных много, в сутки до 2 Гб логов.

                                                                                                                                            Ух ты.
                                                                                                                                              0
                                                                                                                                              Ну и зачем заниматься дефрагментацией на 64 битах, скажем, я не очень понимаю. Да, есть TLB, есть page cache, но это уже всё эффекты следующего порядка малости.

                                                                                                                                              Это в теории на 64 битах все должно быть шоколадно, а на деле оно вафельно. Вот у чувака похожие проблемы: habr.com/post/420579
                                                                                                                                                0
                                                                                                                                                Это, как я понял, какие-то проблемы в реализации ОС (которые, тем более, как он пишет, позже были пофикшены в самой ОС), а не непосредственные свойства режима адресации.
                                                                                                                                                0
                                                                                                                                                Ну и зачем заниматься дефрагментацией на 64 битах, скажем, я не очень понимаю

                                                                                                                                                Каким образом разрядность ОС влияет на проблему фрагментации памяти?
                                                                                                                                                  +1

                                                                                                                                                  Размером виртуального адресного пространства процесса.
                                                                                                                                                  В случае 64-битного процесса вы всегда можете выделить непрерывный кусок памяти любой разумной длины, в случае 32-битного — не можете.

                                                                                                                                                    0
                                                                                                                                                    Увеличение разрядности указателя позволяет всего лишь увеличить объем адресуемого пространства, но никак не решает проблему физической фрагментации памяти.
                                                                                                                                                    Если вы внимательно прочитаете комментарий, то увидите, что речь там идет о мегабайтах, для чего 32 бит вполне достаточно.
                                                                                                                                                      +2

                                                                                                                                                      А почему фрагментация физической памяти — это проблема? И зачем её решать? Или вы пользуетесь операционной системой без виртуализации доступа к памяти?

                                                                                                                                                        0
                                                                                                                                                        Достаточно не очень удачно выделить порядка 2048 мегабайт, чтобы больше ничего выделить не удалось. Ну, на 32 битах без PAE и со стандартными (насколько я помню, для Windows так) двумя гигами виртуальной памяти на юзерспейс.

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

                                                                                                                                              При частом выделении/освобождении памяти обычно применяют пулы объектов вместо кучи, не?


                                                                                                                                              в каком-нибудь банальном цикле поиска

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


                                                                                                                                              для уникода это не годится.

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


                                                                                                                                              Который должен работать годами без остановки

                                                                                                                                              ОС решит дисками пошуршать по своим делам

                                                                                                                                              У меня возникает ощущение, что где-то взяли не подходящий инструмент для решения задачи.

                                                                                                                                                0
                                                                                                                                                При частом выделении/освобождении памяти обычно применяют пулы объектов вместо кучи, не?

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

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

                                                                                                                                                В моем случае это не критично, там больше проблемы с ОСью.

                                                                                                                                                У меня возникает ощущение, что где-то взяли не подходящий инструмент для решения задачи.

                                                                                                                                                А какой инструмент поможет, если слабым звеном оказывается ось и ввод-вывод? Пробовали свою железку делать, на микроконтроллере со своей прошивкой и на нее переложить часть забот, так там свои проблемы — то флеш глючит, то памяти мало, то пропускной способности не хватает.
                                                                                                                                              0
                                                                                                                                              Дают доступ к тому функционалу, который не отвалится в обозримом будущем.
                                                                                                                                              0
                                                                                                                                              openal
                                                                                                                                              — это библиотека для работы со звуком.
                                                                                                                                              java — академически правильный язык
                                                                                                                                              Ой, ну скажите еще, что С — не низкоуровневый язык))) Чем java «академически правильная»?

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

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

                                                                                                                                                    Если уж совсем докапываться до фразы, то программы пишут на языках программирования, с использованием IDE и других инструментов.
                                                                                                                                                    0
                                                                                                                                                    Не спорю, это лишь отсылка к названию статьи.
                                                                                                                                                    0
                                                                                                                                                    Извините ночью писал: Не openal а openacc
                                                                                                                                                    Я вообще не понял что хотел сказать автор. Но категорически с ним не согласен.
                                                                                                                                                    +1
                                                                                                                                                    В модель акторов не панацея она создаёт больше проблем чем решает.

                                                                                                                                                    А что там с акторами? Я топлю не совсем за них (меня больше STM и подобное воодушевляет), но всё равно интересно.

                                                                                                                                                    Постоянное развитие C++ ведёт его в сторону усложнения, как для изучения так и для написания компиляторов.

                                                                                                                                                    На современных плюсах легче писать, чем на плюсах 10-летней давности. И выучить современное подмножество, наверное, проще.

                                                                                                                                                    При этом не решая практических задач. (например php из коробки умеет общаться с базами данных, работать с архивами и т.п.)

                                                                                                                                                    Решение практических задач не входит в круг интересов Комитета, философия языка немного другая.

                                                                                                                                                    Пхп-код уже можно компилировать под attiny?