2016-10-02 7 views
1

фонПроизводительность + = в Java

Недавно я опубликовал ответ рекомендующий что-то вроде: "Пожалуйста, используйте x += 2; вместо"

x = x + 2; 

Кто-то заметил

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

После получения вышеуказанного комментария мне было любопытно, и я сделал быстрый поиск Google и SO, который ничего не вернул.

Мой вопрос

Есть ли разница в производительности между x = x + 2; и x += 2 в Java? Или это единственная разница в читаемости и стиле, что делает выбор между двумя вопросами?

Просьба представить доказательства, а не мнения.

+1

Вы беспокоитесь о _nanoseconds_ здесь. Преждевременная оптимизация. –

+0

Простой «почему?» поскольку ответ на этот комментарий был бы более продуктивным. –

+1

Ваш код был 'x = (x + 2);' и мой комментарий был не о производительности, а о читаемости (поскольку он также избегает избыточного parenthese). – Tom

ответ

1

Ниже приведен компилятор Eclipse (см. Ниже).

Java код:

public static void x(int x) 
{ 
    x = x + 2; 
} 

Байт-код:

public static void x(int); 
    Code: 
    0: iinc   0, 2 
    3: return 

Java код:

public static void x(int x) 
{ 
    x += 2; 
} 

Байт-код:

public static void x(int); 
    Code: 
    0: iinc   0, 2 
    3: return 

Как вы можете видеть, они скомпилируются с одним и тем же байтовым кодом. Компилятор Java сильно оптимизирует ваш код, поэтому не пытайтесь оптимизировать его для мелочи, особенно за счет удобочитаемости.

Редактировать: Оказывается, что не все компиляторы компилируют эти операторы в один и тот же код. Однако исходный момент все еще стоит.Не пытайтесь оптимизировать свой Java-код для тривиальных вещей, особенно за счет удобочитаемости; потому что JIT-компилятор сильно оптимизирует ваш код при компиляции байтового кода в собственный машинный код, даже если некоторые компиляторы Java пропускают некоторые оптимизации.

+2

Какая версия java вы используете? У меня есть другой байт-код для этих двух операторов –

+0

Я использую версию 1.7.0_51. вы используете? – uoyilmaz

+0

Я использую версию 1.8.0_101. –

-1

Компилятор выполняет оба оператора таким же образом, и нет никакой разницы во времени выполнения или производительности. x+=2 интерпретируется компилятором как x = x + 2 и не должен иметь разницы во времени выполнения.

+0

любые доказательства этого? – nhouser9

+0

Я нашел [это] (http://stackoverflow.com/questions/7471891/is-x-1-more-efficient-than-x-x-1) пост. –

+1

Это Q & A для C. Компилятор Java рассматривает '+ =' по-разному. Это может не повлиять на производительность, но есть разница. – Tom

0

Я считаю, что единственное различие - читаемость. При изучении этого в классе нам сказали, что x += 2 на самом деле менее распространен.

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

This other Вопрос относится только к Java и предоставляет гораздо больше доказательств.

+0

любые доказательства того, что компилятор относится к ним одинаково? – nhouser9

+1

* «на самом деле реже» * Я сомневаюсь, что ... высоко. – Tom

+0

@Tom Я пошел в хороший инженерный университет и большинство моих друзей, и я никогда не пишу + = для простого целочисленного добавления; мы считаем это гораздо менее удобочитаемым. – nhouser9

0

Сгенерированные байт-коды для двух частей кода различны на моей машине (как, скорее всего, на вашем), но это не имеет значения. Во-первых, машинный код, фактически выполняемый JVM после оптимизации, может быть одинаковым; во-вторых, на практике вы не заметите никакой разницы. Попробуйте сравнить его самостоятельно (это PDF presentation объясняет, почему вы не должны), скажем, в цикле, и вы увидите, что вы получаете всевозможные результаты, которые могут отличаться n-fold между прогонами и/или после незначительных изменений, и что происходит в окружении, которое вы сделали настолько предсказуемым, насколько сможете. Представьте, что происходит в реальном коде, где любая из этих строк - это не случайный существенный CPU-spender.

Запуск надлежащего JMH микрофункции для этого кода говорит, что он работает в ~ 3-4 наносекундах в обоих вариантах (вместе с загрузкой начального значения из поля и возвратом результата из метода, или же весь метод может быть выброшен далеко). Я немного скептически отношусь к тому, что некоторые фреймворки могут измерять время с такой точностью на моем рабочем столе, но я думаю, что либо это истина, либо фактические тайминги этих двух частей кода заглушаются другими затратами (вызов метода? Loading значение? возвращающее значение?).

Benchmark  Mode Cnt  Score  Error Units 
MyBenchmark.f1 thrpt 30 281747,576 ± 9748,881 ops/ms 
MyBenchmark.f2 thrpt 30 289411,317 ± 8951,254 ops/ms 

Ради полноты картины, эталоном я использовал

import org.openjdk.jmh.annotations.*; 
import java.util.concurrent.*; 

@State(Scope.Thread) 
@OutputTimeUnit(TimeUnit.MILLISECONDS) 
public class MyBenchmark { 

    public int a = 0xDEADBEAF; 

    @Benchmark 
    public int f1() { 
     int x = a; 
     x += 2; 
     return x; 
    } 

    @Benchmark 
    public int f2() { 
     int x = a; 
     x = x + 2; 
     return x; 
    } 
} 

Выполнить 10 итераций прогрева, 10 измерительных итераций, 3 вилки.