Я удивлен, увидев столько ответов, требующих кодирования, чтобы изменить один вариант использования (GET) в one API вместо того, чтобы использовать правильный инструмент, который должен быть установлен один раз и может использоваться для любой API (собственный или сторонний) и все варианты использования.
Итак, хороший ответ:
О, я не знаю. Иногда компиляторы довольно умны. Рассмотрите следующую программу C:
#include <stdio.h> /* printf() */
int factorial(int n) {
return n == 0 ? 1 : n * factorial(n - 1);
}
int main() {
int n = 10;
printf("factorial(%d) = %d\n", n, factorial(n));
return 0;
}
На моей версии [1 111] GCC (4.3.2 на [1 112] тестирование Debian), когда скомпилировано без оптимизации, или -O1
, это генерирует код для factorial()
как, Вы ожидали бы, с помощью рекурсивного вызова для вычисления значения. Но на -O2
, это делает что-то интересное: Это компилирует вниз в жесткий цикл:
factorial:
.LFB13:
testl %edi, %edi
movl $1, %eax
je .L3
.p2align 4,,10
.p2align 3
.L4:
imull %edi, %eax
subl $1, %edi
jne .L4
.L3:
rep
ret
Довольно впечатляющий. Рекурсивный вызов (даже не рекурсивный хвостом) был полностью устранен, таким образом факториал теперь использует O (1) стековое пространство вместо O (N). И хотя у меня есть только очень поверхностное знание x86 блока (на самом деле AMD64 в этом случае, но я не думаю, что любое из расширений AMD64 используется выше), я сомневаюсь, что Вы могли записать лучшую версию вручную. Но что действительно дуло, мой ум был кодом, который он генерировал на -O3
. Реализация факториала осталась такой же. Но main()
измененный:
main:
.LFB14:
subq $8, %rsp
.LCFI0:
movl $3628800, %edx
movl $10, %esi
movl $.LC0, %edi
xorl %eax, %eax
call printf
xorl %eax, %eax
addq $8, %rsp
ret
Посмотрите movl $3628800, %edx
строка? gcc предварительно вычисляет factorial(10)
во время компиляции. Это даже не звонит factorial()
. Невероятный. Моя шляпа прочь группе разработчиков GCC.
, Конечно, все обычные правовые оговорки применяются, это - просто игрушечный пример, преждевременная оптимизация является корнем всего зла, и т.д., и т.д., но это иллюстрирует, что компиляторы часто более умны, чем Вы думаете. Если Вы думаете, что можно сделать лучшее задание вручную, Вы почти наверняка неправы.
(Адаптированный от регистрация на моем блоге .)
Это вынуждает Вас (программист) думать о том, что Вы пишете. Вынуждая компиляторы сделать Ваша работа для Вас не помогает никому: это делает компиляторы намного более сложными (и медленнее!), и это делает Вас более глупыми и менее внимательными к Вашему коду.
Значение Ваших двух примеров бессмысленно, бесполезно и только сделанное одурачить компилятор.
компилятор не способен (и не должен быть) видеть значение метода, цикла или программы. Это - то, где Вы входите в изображение. Вы создаете метод для определенной функциональности/значения, неважно, насколько глупый это. Это - тот же случай для простых проблем или экстремальных сложных программ.
В Вашем случае компилятор мог бы оптимизировать его, потому что это "думает", что должно быть оптимизировано в другом отношении, но почему остаются там?
Экстремальное значение другая ситуация. У нас есть умный компилятор, компилирующий Windows. Тонны кода для компиляции. Но если это умно, это сводит его к 3 строкам кода...
"starting windows"
"enjoy freecell/solitaire"
"shutting down windows"
Остальная часть кода является устаревшей, потому что это никогда не используется, затрагивается, получается доступ. Мы действительно хотим это?
Это - пример функционального кода процессуального кодекса v.
Вы подробно изложили процедуру компилятора для следования, таким образом, оптимизации будут основанными вокруг подробной процедуры и минимизируют любые побочные эффекты или не оптимизируют, где это не будет делать то, что Вы ожидаете. Это облегчает отлаживать.
, Если Вы вставляете функциональное описание того, что Вы хотите, например, SQL тогда, Вы даете компилятору широкий спектр опций оптимизировать.
, Возможно, некоторый тип анализа кода был бы в состоянии найти этот тип проблемы или представляющий во времени выполнения, но тогда Вы захотите изменить источник на что-то более разумное.
Абсолютная оптимизация является неразрешимой проблемой, которая означает, нет никакой Машины Тьюринга (и, поэтому, никакая компьютерная программа), который может привести к оптимальной версии ЛЮБОЙ данной программы.
Некоторая простая оптимизация может быть (и, на самом деле), сделанный, но, в примерах Вы дали...
, Чтобы обнаружить, что Ваша первая программа всегда печатает нуль, компилятор должен был бы обнаружить, что x остается постоянным несмотря на все повторения цикла. Как может Вы объяснять (я знаю, это не лучшее слово, но я не могу придумать другого), это к компилятору?
, Как компилятор может знать, что StringBuilder является правильным инструментом для задания без КАКОЙ-ЛИБО ссылки на него?
В реальном приложении, если эффективность очень важна в части Вашего приложения, она должна быть записана на низкоуровневом языке как C. (Ха-ха, серьезно, я записал это?)
Поскольку разработчики компилятора пробуют, добавляет оптимизация для вещей, которые имеют значение (я надеюсь), и которые измеряются в *сравнительные тесты Stone (я боюсь).
существует огромное количество других возможных фрагментов кода как Ваши, которые ничего не делают и могли быть оптимизированы с увеличивающимся усилием на разработчике компилятора, но с которыми почти никогда не встречаются.
то, Что я чувствую себя смущающим, - то, что даже сегодня большинство компиляторов генерирует код для проверки на switchValue быть больше, чем 255 для плотного или почти полного переключателя на неподписанном символе. Это добавляет 2 инструкции к большей части внутреннего цикла интерпретатора байт-кода.
Я никогда не видел точку в устранении мертвого кода во-первых. Почему программист писал его?? Если Вы собираетесь сделать что-то о мертвом коде, объявите его ошибка компилятора! Это почти наверняка означает, что программист сделал ошибку - и для нескольких случаев это не делает, директива компилятора для использования переменной была бы надлежащим ответом. Если я поместил мертвый код в стандартную программу, я хочу выполняемый - я, вероятно, планирую осмотреть результаты в отладчике.
случай, где компилятор мог делать некоторое хорошее, вытаскивает инварианты цикла. Иногда ясность говорит для кодирования вычисления в цикле, и наличие компилятора выходят, такие вещи были бы хороши.
Это почти полагало, что плохая практика оптимизирует вещи как это при компиляции вниз в байт-код JVM. Sun javac
действительно имеет некоторую основную оптимизацию, как делает scalac
, groovyc
, и т.д. Короче говоря, что-либо, что это является истинно определенным для языка, может быть оптимизирован в рамках компилятора. Однако вещи как это, которые, очевидно, изобретены так, чтобы быть агностиком языка, уменьшатся через просто из политики.
причина этого - он, позволяет HotSpot иметь намного более последовательное представление байт-кода и его шаблонов. Если компиляторы начинают слоняться без дела с пограничными случаями, который уменьшает способность VM оптимизировать общий случай, который не может быть очевидным во время компиляции. Steve Yeggie нравится к арфе на приблизительно этом: оптимизация часто легче , когда выполнено во времени выполнения умной виртуальной машиной. Он даже идет, насколько утверждать, что HotSpot разделяет оптимизацию javac. В то время как я не знаю, верно ли это, это не удивило бы меня.
Для суммирования: компиляторы, предназначающиеся для VMs, имеют совсем другой набор критериев, особенно в области оптимизации и когда это является соответствующим. Не идите, обвиняя разработчики компилятора в отъезде работы к far-more-capable JVM. Как указано несколько раз на этом потоке, современные компиляторы, предназначающиеся для собственной архитектуры (как gcc
семья), чрезвычайно умны, производя неприлично быстрый код посредством некоторой очень умной оптимизации.
Главным образом то, на что Вы жалуетесь, 'почему компилятор Java, таким образом, глупый', так как большинство других языковых компиляторов намного более умно.
причина глупости компиляторов Java является исторической. Во-первых, исходные реализации Java были интерпретатором, базирующимся, и производительность была consisdered неважный. Во-вторых, многие исходные сравнительные тесты Java были проблематичны для оптимизации. Я вспоминаю один сравнительный тест, который походил много на Ваш второй пример. К сожалению, если бы компилятор оптимизировал цикл далеко, сравнительный тест получил бы деление нулевым исключением, когда это пыталось разделить базовое число к прошедшему времени для вычисления его счета производительности. Таким образом, при записи компилятора Java оптимизации, необходимо было очень бояться оптимизировать некоторые вещи, поскольку люди тогда утверждали бы, что компилятор был поврежден.
Я думаю, что Вы недооцениваете, сколько работы это должно удостовериться, что одна часть кода не влияет на другую часть кода. С просто небольшим изменением Ваших примеров x, я и s могли все указать на ту же память. Как только одна из переменных является указателем, намного более трудно сказать то, в зависимости от чего код мог бы иметь побочные эффекты, точка к какой.
кроме того, я думаю люди, которые программируют компиляторы, потратили бы оптимизацию создания времени, которая не так легка для людей сделать.
Поскольку мы просто не там все же. Вы, возможно, столь же легко спросили, "почему я должен все еще записать программы..., почему я не могу только питаться в документе требований и иметь компьютер, пишут приложение для меня?"
Разработчики компилятора проводят время на небольших вещах, потому что те - типы вещей, которые прикладные программисты склонны пропускать.
кроме того, они не могут принять слишком много (возможно, Ваш цикл, некоторое гетто было задержкой или чем-то)?
Компиляторы в целом очень умны.
то, Что необходимо рассмотреть, - то, что они должны составлять каждый возможно исключение или ситуация, где оптимизация или рефакторинг кода могли вызвать нежелательные побочные эффекты.
Вещи как, потоковые программы, искажение указателя, динамично связали код, и побочные эффекты (системное выделение вызовов/памяти) и т.д. делают официально доказательство рефакторинга очень трудным.
Даже при том, что Ваш пример прост, все еще может быть трудными ситуациями для рассмотрения.
Что касается Вашего аргумента StringBuilder, который НЕ является заданием компиляторов для выбора который структуры данных использовать для Вас.
, Если Вы хотите более мощное перемещение оптимизаций на язык более со строгим контролем типов как Фортран или haskell, где компиляторам дают намного больше информации для работы с.
Большинство курсов обучающие компиляторы/оптимизация (даже acedemically) дают смысл оценки о том, как, делая gerneral официально оптимизации продуховки вместо того, чтобы взломать конкретные случаи являются очень трудной проблемой.
Это - вечная гонка вооружений между разработчиками компилятора и программистами.
Неизобретенные примеры работают отлично - большинство компиляторов действительно оптимизирует далеко очевидно бесполезный код.
Изобретенный исследует, будет всегда , озадачивают компилятор. Доказательство, если кто-либо был необходим, что любой программист более умен, чем какая-либо программа.
В будущем, Вам будут нужны более изобретенные примеры, чем, Вы отправили здесь.
На Вашем первом примере это - оптимизация, которая только работает, если значение является нулем. Дополнительное if
оператор в компиляторе должен был искать этот редко замеченный пункт, может не просто стоить того (так как это должно будет проверить на это на каждой переменной). Кроме того, что относительно этого:
int x = 1;
int y = 1;
int z = x - y;
for (int i = 0; i < 100 * 1000 * 1000 * 1000; ++i) {
z += z + z + z + z + z;
}
System.out.println(z);
Это - все еще, очевидно, то же самое, но теперь существует дополнительный случай, для которого мы должны кодировать в компиляторе. Существует только бесконечная сумма способов, которыми она может закончить тем, что была нулем, в которых не стоит кодировать для, и я предполагаю, что Вы могли сказать, что, если Вы собираетесь иметь одного из них, Вы были бы, мог бы также иметь их всех.
Некоторая оптимизация действительно заботится о втором примере, который Вы отправили, но я думаю, что видел его больше на функциональных языках и не таком большом количестве Java. Большая вещь, которая затрудняет на более новых языках, исправление обезьяны . Теперь +=
может иметь побочный эффект , который означает, оптимизируем ли мы его, это потенциально неправильно (например, добавляющая функциональность к +=
, который распечатывает текущее значение, будет означать различную программу в целом).
, Но это сводится к тому же самому снова и снова: существует только слишком много случаев, которые необходимо было бы искать, чтобы удостовериться, что никакие побочные эффекты не выполняются, который потенциально изменит состояние заключительной программы.
просто легче занять дополнительный момент и удостовериться, что Вы пишете, то, что Вы действительно хотите, чтобы компьютер сделал.:)
Серьезно? Почему кто-либо когда-либо писал бы реальный код как этот? По моему скромному мнению, код, не компилятор является "глупым" объектом здесь. Я для каждый совершенно рад, что разработчики компилятора не потрудились тратить впустую свое время, пытаясь оптимизировать что-то как этот.
Редактирование/Разъяснение: я знаю, что код в вопросе предназначен как пример, но это просто подтверждает мою точку зрения: или необходимо пробовать, или быть довольно невежественными для записи в высшей степени неэффективного кода как этот. Это не задание компилятора для содержания нашей руки, таким образом, мы не пишем ужасный код. Именно наша ответственность в качестве людей пишет код для знания достаточно о наших инструментах для записи эффективно и ясно.
JIT-компилятор HotSpot только оптимизирует код, который работал в течение некоторого времени. К тому времени, когда Ваш код является горячим, цикл был уже запущен, и JIT-компилятор должен ожидать до следующего раза метод вводится для поиска способов оптимизировать далеко цикл. При вызове метода несколько раз Вы могли бы видеть лучшую производительность.
Это покрыто в HotSpot FAQ под вопросом, "Я пишу простой цикл во время простая операция, и это медленно. Что я делаю неправильно?".
Разговор с точки зрения C/C++:
Ваш первый пример будет оптимизирован большинством компиляторов. Если компилятор Java от Sun действительно выполняет этот цикл, это - отказ компиляторов, но честное слово что любое сообщение 1990 C, C++ или компилятор Фортрана полностью устраняет такой цикл.
Ваш второй пример не может быть оптимизирован на большинстве языков, потому что выделение памяти происходит как побочный эффект конкатенации строк вместе. Если бы компилятор оптимизировал бы код, шаблон выделения памяти изменился бы, и это могло привести к эффектам, которых старается избегать программист. Фрагментация памяти и связанные проблемы являются проблемами, которые встроили программистов, все еще стоят каждый день.
Полный я удовлетворен компиляторами оптимизации, может сделать в эти дни.
Компиляторы разработаны, чтобы быть предсказуемы . Это может заставить их выглядеть глупыми время от времени, но это в порядке. Цели разработчика компилятора
, необходимо быть в состоянии посмотреть код и сделать разумные прогнозы о его производительности.
Небольшие изменения в коде не должны приводить к резким различиям в производительности.
, Если небольшое изменение смотрит на программиста как он, должен улучшить производительность, это не должно, по крайней мере, ухудшать производительность (если удивительные вещи не происходят в аппаратных средствах).
Все эти критерии препятствуют "волшебной" оптимизации, которая применяется только к угловым случаям.
<час>Обоим из Ваших примеров обновили переменная в цикле, но не используемые в другом месте . Этот случай на самом деле довольно трудно взять, если Вы не используете своего рода платформу, которая может объединить устранение невыполняемого кода с другой оптимизацией как распространение копии или постоянное распространение. К простой оптимизатор потока данных переменная не выглядит мертвой. Для понимания, почему эта проблема трудна посмотрите статья Lerner, Рощи и Камер в 2002 POPL , который использует этот самый пример и объясняет, почему это твердо.
По-моему, я не полагаю, что это - задание компилятора для фиксации то, что, честно, плохо кодирует. Вы, вполне явно, сказали компилятору о желании того первого выполняемого цикла. Это совпадает с:
x = 0
sleep 6 // Let's assume this is defined somewhere.
print x
я не хотел бы компилятор, удаляющий мой sleep
оператор просто, потому что это ничего не сделало. Можно утверждать, что оператор сна является явным запросом на задержку, тогда как пример не. Но тогда Вы будете позволять компилятору принимать очень высокоуровневые решения относительно того, что должен сделать Ваш код, и я полагаю что быть плохой вещью.
Код и компилятор, который обрабатывает его, являются инструментами, и необходимо быть системным программистом, если Вы хотите использовать их эффективно. Сколько 12-дюймовые цепные пилы откажутся пробовать сокращенный 30-дюймовое дерево? Сколько разверток автоматически переключится для стука режима, если они обнаружат бетонную стену?
Ни один, который я подозреваю, и это вызвано тем, что стоимость разработки этого в продукт была бы ужасающей для запуска. Но что еще более важно, Вы не должны использовать развертки или цепные пилы, если Вы не знаете то, что Вы делаете. Например: если Вы не знаете то, что вознаграждение (очень простой способ к новичку снять их руку), избегать цепных пил, пока Вы не делаете.
я, все для разрешения компиляторов к предлагает улучшения, но я обеспечил бы контроль сам. Это не должно быть до компилятора, чтобы решить в одностороннем порядке, что цикл является ненужным.
, Например, я сделал циклы синхронизации во встроенных системах, где тактовая частота ЦП известна точно, но никакое надежное устройство синхронизации не доступно. В этом случае можно вычислить точно, сколько времени данный цикл будет брать и использовать это для управления, как часто вещи происходят. Это не работало бы, если бы компилятор (или ассемблер в этом случае) решил, что мой цикл был бесполезен и оптимизировал его из существования.
Однако позвольте мне оставить Вас со старой историей компилятора ФОРТРАНА VAX, который подвергался сравнительному тесту для производительности, и было найдено, что это было многие порядки величины быстрее, чем его самый близкий конкурент.
оказывается, что компилятор заметил, что результат циклов сравнительного теста не использовался больше нигде и оптимизировал циклы в забвение.
Поскольку другие обратились к первой части Вашего вопроса соответственно, я попытаюсь заняться второй частью, т.е. "автоматически использует StringBuilder вместо этого".
существует несколько серьезных оснований для того, чтобы не сделать то, что Вы предлагаете, но самый большой фактор на практике вероятен, что выполнения оптимизатора после фактического исходного кода были переварены & забытый о. Оптимизаторы обычно воздействуют или на сгенерированный код байта (или на блок, три адресных кода, машинный код, и т.д.), или на абстрактных синтаксических деревьях, которые следуют из парсинга кода. Оптимизаторы обычно не знают ничего из библиотек времени выполнения (или никакие библиотеки вообще), и вместо этого работают на уровне инструкции (то есть, низкоуровневый поток управления и выделение регистра).
112-секундный, поскольку библиотеки развиваются (особенно в Java) намного быстрее, чем языки, не отставая от них и зная то, что удерживает от использования то, какой и что другой компонент библиотеки мог бы лучше подходить для задачи, будет гераклова задача. Также, вероятно, невозможный, поскольку этот предложенный оптимизатор должен был бы точно понять и Ваше намерение и намерение каждого доступного компонента библиотеки, и так или иначе найти отображение между ними.
Наконец, как другие сказали (я думаю), писатель компилятора/оптимизатора может обоснованно предположить, что программист, пишущий входной код, не является глупым. Это была бы пустая трата времени для посвящения значительного усилия глупым особым случаям как они, когда другой, более общая оптимизация имеется в большом количестве. Кроме того, как другие также упомянули, на вид глупый код может иметь фактическую цель (спин-блокировка, активное ожидание до урожая системного уровня, и т.д.), и компилятор должен соблюдать то, что программист просит (если это синтаксически и семантически допустимо).
Компиляторы так умны, как мы делаем их. Я не знаю слишком много программистов, которые потрудились бы писать компилятор, который проверит на конструкции, такие как те, Вы использовали. Большая часть концентрата на более типичных способах улучшить производительность.
возможно, что когда-нибудь у нас будет программное обеспечение, включая компиляторы, которые могут на самом деле учиться и вырасти. Когда в тот день прибудет больше всего, возможно, все, программисты будут без работы.
На самом деле Java должен использовать строкового разработчика в Вашем втором примере.
основная проблема с попыткой оптимизировать эти примеры далеко состоит в том, что выполнение так потребовало бы доказательство теорем . То, что означает, что компилятор должен был бы создать математическое доказательство того, что Вы - код, на самом деле сделает. И это не маленькая задача вообще. На самом деле способность доказать, что весь код действительно имеет эффект, эквивалентна проблеме остановки.
Несомненно, можно придумать тривиальные примеры, но количество тривиальных примеров неограниченно. Вы могли всегда думать о чем-то еще, таким образом, нет никакого способа поймать их всех.
, Конечно, возможно для [приблизительно 111] код, как доказывать, не иметь любой эффект, как в Ваших примерах. То, что Вы хотели бы сделать, имеют компилятор, оптимизируют далеко каждую проблему, которая может быть доказана неиспользованной во время P.
, Но так или иначе, это - тонна работы, и это не получает Вас всех так очень. Люди проводят много времени, пытаясь выяснить способы препятствовать тому, чтобы программы имели ошибки в них, и системы типов как те в Java и Scala являются попытками предотвратить ошибки, но прямо сейчас никто не использует системы типов для создания операторов о времени выполнения, насколько я знаю.
Вы могли бы хотеть изучить Haskel, который я думаю, имеет самую усовершенствованную теорию, доказывающую материал, хотя я не уверен в этом. Я не знаю это сам.
Вы компилировали для выпуска кода? Я думаю, что хороший компилятор обнаруживает в Вашем втором примере, что строка никогда не используется удалять весь цикл.
Ну, я могу только говорить о C++, потому что я - новичок Java полностью. В C++ компиляторы являются бесплатными игнорировать любые требования языка, помещенные Стандартом, пока заметный , поведение , как будто компилятор на самом деле эмулировал все правила, которые помещаются Стандартом. Заметное поведение определяется как [1 121] любые чтения и записи к энергозависимым данным и вызовы к библиотечным функциям . Рассмотрите это:
extern int x; // defined elsewhere
for (int i = 0; i < 100 * 1000 * 1000 * 1000; ++i) {
x += x + x + x + x + x;
}
return x;
компилятору C++ позволяют оптимизировать, что часть кода и просто добавляет собственное значение к x, который следовал бы из того цикла однажды, потому что код ведет себя , как будто цикла никогда не происходило, и никакие энергозависимые данные, ни библиотечные функции включены, который мог вызвать необходимые побочные эффекты. Теперь рассмотрите энергозависимые переменные:
extern volatile int x; // defined elsewhere
for (int i = 0; i < 100 * 1000 * 1000 * 1000; ++i) {
x += x + x + x + x + x;
}
return x;
компилятор не , позволил делать ту же оптимизацию больше, потому что не может оказаться, что побочные эффекты, вызванные путем записи в x
, не могли влиять на заметное поведение программы. В конце концов, x мог быть установлен на элемент памяти, наблюдаемый некоторым устройством, которое инициирует в каждой записи.
Разговор о Java, я протестировал Ваш цикл, и это происходит, который Компилятор Java GNU (gcj
) берет в беспорядочном количестве времени для окончания цикла (это просто не закончилось, и я уничтожил его). Я включил флаги оптимизации (-O2), и это произошло, это распечатало 0
сразу:
[js@HOST2 java]$ gcj --main=Optimize -O2 Optimize.java
[js@HOST2 java]$ ./a.out
0
[js@HOST2 java]$
, Возможно, что наблюдение могло быть полезным в этом потоке? Почему это, оказывается, так быстро для gcj? Ну, одна причина, конечно, состоит в том, что gcj компилирует в машинный код, и таким образом, это не имеет никакой возможности оптимизировать тот код на основе поведения во время выполнения кода. Это берет всю свою крепкость вместе и пытается оптимизировать столько, сколько это может во время компиляции. Виртуальная машина, однако, может скомпилировать код Как раз вовремя как этот вывод шоу Java этого кода:
class Optimize {
private static int doIt() {
int x = 0;
for (int i = 0; i < 100 * 1000 * 1000 * 1000; ++i) {
x += x + x + x + x + x;
}
return x;
}
public static void main(String[] args) {
for(int i=0;i<5;i++) {
doIt();
}
}
}
Вывод для java -XX:+PrintCompilation Optimize
:
1 java.lang.String::hashCode (60 bytes)
1% Optimize::doIt @ 4 (30 bytes)
2 Optimize::doIt (30 bytes)
, Как мы видим, это, JIT компилирует функцию мелкой монеты 2 раза. На основе наблюдения за первым выполнением это компилирует его во второй раз. Но это, оказывается, имеет тот же размер как байт-код два раза, предполагая, что цикл все еще на месте.
, Поскольку другой программист показывает, время выполнения для определенных мертвых циклов даже увеличено для некоторых случаев для впоследствии скомпилированного кода. Он сообщил об ошибке, которая может быть считана здесь и является с 24. Октябрь 2008.
Компиляторы, которые могут выполнять оптимизацию со строгим псевдонимом, оптимизируют первый пример. См. здесь .
Второй пример не может быть оптимизирован, потому что самая медленная часть здесь - это выделение / перераспределение памяти, а оператор + = переопределяется в функцию, которая выполняет работу с памятью. В разных реализациях строк используются разные стратегии распределения.
Я тоже предпочел бы иметь malloc (100000), чем тысячу malloc (100) при выполнении s + = "s"; но сейчас эта вещь выходит за рамки компиляторов и должна быть оптимизирована людьми. Это то, что язык D пытается решить, вводя чистые функции .
Как упоминалось здесь в других ответах,