Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
public class Test {
public static void main(String[] args) {
String s = "Some " + "string " + 1 + " concatenated: " + 2L + ":" + (byte)3 + ":" + 1.0d;
System.out.println(s);
String s2 = "Another one " + args[0] + args[1] + args[2] + args[3];
System.out.println(s2);
}
}
public static void main(java.lang.String[]);
Code:
0: ldc #2 // String Some string 1 concatenated: 2:3:1.0
2: astore_1
3: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
6: aload_1
7: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
10: new #5 // class java/lang/StringBuilder
13: dup
14: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V
17: ldc #7 // String Another one
19: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: aload_0
23: iconst_0
24: aaload
25: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: aload_0
29: iconst_1
30: aaload
31: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
34: aload_0
35: iconst_2
36: aaload
37: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
40: aload_0
41: iconst_3
42: aaload
43: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
46: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
49: astore_2
50: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
53: aload_2
54: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
57: return
}
The Java language provides special support for the string concatenation operator ( + ), and for conversion of other objects to strings. String concatenation is implemented through the StringBuffer class and its append method. String conversions are implemented through the method toString, defined by Object and inherited by all classes in Java. For additional information on string concatenation and conversion, see Gosling, Joy, and Steele, The Java Language Specification.
g[i][i] = i << 2; for (int[] row : arr)
Arrays.fill(row, 1);
class A {
public static void main(String[] args) {
int n = 8000;
int g[][] = new int[n][n];
long st, en;
// one
st = System.nanoTime();
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
g[i][j] = 1;
}
}
en = System.nanoTime();
System.out.println("\nTwo time " + (en - st)/1000000.d + " msc");
// two
st = System.nanoTime();
for(int j = 0; j < n; j++) {
for(int i = 0; i < n; i++) {
g[i][j] = 1;
}
}
en = System.nanoTime();
System.out.println("\nTwo time " + (en - st)/1000000.d + " msc");
}
}
class A {
public static void main(String[] args) {
int n = 5000;
int g[][] = new int[n][n];
long st, en;
// one
st = System.nanoTime();
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
g[i][j] = 10;
}
}
en = System.nanoTime();
System.out.println("\nTwo time " + (en - st)/1000000.d + " msc");
// two
st = System.nanoTime();
for(int i = 0; i < n; i++) {
g[i][i] = 20;
for(int j = 0; j < i; j++) {
g[j][i] = g[i][j] = 20;
}
}
en = System.nanoTime();
System.out.println("\nTwo time " + (en - st)/1000000.d + " msc");
// 3 Обычный массив такого же размера, как и двухмерный, линейный проход по всем элементам
int arrLen = n*n;
int[] arr = new int[arrLen];
st = System.nanoTime();
for(int i : arr) {
arr[i] = 30;
}
en = System.nanoTime();
System.out.println("\n3 time " + (en - st)/1000000.d + " msc");
// 4 Тот же массив, но работаем как с двухменым массом
st = System.nanoTime();
int i, j;
for(i = 0; i < n; i++) {
for(j = 0; j < n; j++) {
arr[i*n+j] = 40;
}
}
en = System.nanoTime();
System.out.println("\n4 time " + (en - st)/1000000.d + " msc");
}
}
Two time 71.998012 mscTwo time 551.664166 msc3 time 63.74851 msc4 time 57.215167 mscСтрого говоря в Java вообще нет двумерных массивов, поэтому автор всех здорово запутал своими параллелями с Си и Паскалем. Видимо отсюда и весь налет мистики.
int a[][] = new int[N][K]
int b[] = new int[N*K];
a != b;
int[][] nums = new int[3][6];
public class Test2 {
public static void main(String[] args) {
int n = 8000;
int g = new int[n*n];
long st, en;
// one
st = System.nanoTime();
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
g[i*n + j] = i + j;
}
}
en = System.nanoTime();
System.out.println("\nOne time " + (en - st)/1000000.d + " msc");
// two
st = System.nanoTime();
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
g[j*n + i] = i + j;
}
}
en = System.nanoTime();
System.out.println("\nTwo time " + (en - st)/1000000.d + " msc");
}
}
g[j], чтение его длины, проверка на границы при записи i-го элемента, весь фарш. А когда во внутреннем цикле обращаются только к одному массиву g[i], это все JIT выносит за цикл.import org.openjdk.jmh.annotations.*;
import java.util.concurrent.TimeUnit;
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OperationsPerInvocation(ArrayFill.N * ArrayFill.N)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class ArrayFill {
public static final int N = 380;
public int[][] g;
@Setup
public void setup() {
g = new int[N][N];
}
@GenerateMicroBenchmark
public int simple(ArrayFill state) {
int[][] g = state.g;
for(int i = 0; i < g.length; i++) {
for(int j = 0; j < g[i].length; j++) {
g[i][j] = i + j;
}
}
return g[g.length - 1][g[g.length - 1].length - 1];
}
@GenerateMicroBenchmark
public int optimized(ArrayFill state) {
int[][] g = state.g;
for(int i = 0; i < g.length; i++) {
g[i][i] = 2* i;
for(int j = 0; j < i; j++) {
g[j][i] = g[i][j] = i + j;
}
}
return g[g.length - 1][g[g.length - 1].length - 1];
}
}
Что там еще?Разворачивание цикла, а в усложненном варианте — нет (предположение)
// test-time.cpp : main project file.
#include "stdafx.h"
#include <windows.h>
#include <iostream>
using namespace System;
__int64 GetTime()
{
__int64 value = 0;
QueryPerformanceCounter((LARGE_INTEGER *)&value);
return value;
}
int main(array<System::String ^> ^args)
{
int n = 8000;
int* g = new int[n*n];
__int64 st, en;
// one
st = GetTime();
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
g[i*n +j] = i + j;
}
}
en = GetTime();
std::cout << "\n1 time ";
std::cout << (en - st);
// two
st = GetTime();
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
g[j*n +i] = i + j; //j и i меняем местами
}
}
en = GetTime();
std::cout << "\n1 time ";
std::cout << (en - st);
Console::ReadKey();
return 0;
}
</spoiler>
35: aaload
36: iload_3
37: aload_1
38: iload_3
39: aaload
40: iload_2
41: iload_2
42: iload_3
43: iadd
44: dup_x2
45: iastore
46: iastore
27: aaload
28: iload_3
29: iload_2
30: iload_3
31: iadd
32: iastore
One time 2072.3487 msc Two time 1246.582756 msc
gTmp[0] = -999;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
System.out.print(g[i][j] + " ");
}
System.out.println();
}
st = System.nanoTime();
for (int i = 0; i < n; i++) {
gTmp[i] = 1;
}
for (int j = 0; j < n; j++) {
System.arraycopy(gTmp, 0, g[j], 0, n);
}
en = System.nanoTime();
Но мне все-таки правда интересно, где и в каких проектах такая оптимизация может быть полезной? Ведь по сути это экономия на спичках, а если нет, и правда нужна каждая миллисекунда при обработке матриц больших размеренностей, то неужели для java нет jni библиотеки для таких типовых операций на матрицах?

Project3.dpr.16: for i:=1 to n-1 do
0040712F 8B1D98BB4000 mov ebx,[$0040bb98]
00407135 4B dec ebx
00407136 85DB test ebx,ebx
00407138 7E2C jle $00407166
0040713A B901000000 mov ecx,$00000001
Project3.dpr.17: for j:=1 to n-1 do
0040713F 8B1598BB4000 mov edx,[$0040bb98]
00407145 4A dec edx
00407146 85D2 test edx,edx
00407148 7E18 jle $00407162
0040714A B801000000 mov eax,$00000001
Project3.dpr.18: g[i,j] := i + j;
0040714F 8B359CBB4000 mov esi,[$0040bb9c]
00407155 8B348E mov esi,[esi+ecx*4]
00407158 8D3C08 lea edi,[eax+ecx]
0040715B 893C86 mov [esi+eax*4],edi
0040715E 40 inc eax
Project3.dpr.17: for j:=1 to n-1 do
0040715F 4A dec edx
00407160 75ED jnz $0040714f
Project3.dpr.18: g[i,j] := i + j;
00407162 41 inc ecx
Project3.dpr.16: for i:=1 to n-1 do
00407163 4B dec ebx
00407164 75D9 jnz $0040713f
Project3.dpr.22: for i:=1 to n-1 do
004071E2 8B1D98BB4000 mov ebx,[$0040bb98]
004071E8 4B dec ebx
004071E9 85DB test ebx,ebx
004071EB 7E2C jle $00407219
004071ED B901000000 mov ecx,$00000001
Project3.dpr.23: for j:=1 to n-1 do
004071F2 8B1598BB4000 mov edx,[$0040bb98]
004071F8 4A dec edx
004071F9 85D2 test edx,edx
004071FB 7E18 jle $00407215
004071FD B801000000 mov eax,$00000001
Project3.dpr.24: g[j,i] := i + j;
00407202 8B359CBB4000 mov esi,[$0040bb9c]
00407208 8B3486 mov esi,[esi+eax*4]
0040720B 8D3C08 lea edi,[eax+ecx]
0040720E 893C8E mov [esi+ecx*4],edi
00407211 40 inc eax
Project3.dpr.23: for j:=1 to n-1 do
00407212 4A dec edx
00407213 75ED jnz $00407202
Project3.dpr.24: g[j,i] := i + j;
00407215 41 inc ecx
Project3.dpr.22: for i:=1 to n-1 do
00407216 4B dec ebx
00407217 75D9 jnz $004071f2
00407155 8B348E mov esi,[esi+ecx*4]
00407158 8D3C08 lea edi,[eax+ecx]
0040715B 893C86 mov [esi+eax*4],edi
00407208 8B3486 mov esi,[esi+eax*4]
0040720B 8D3C08 lea edi,[eax+ecx]
0040720E 893C8E mov [esi+ecx*4],edi
Пока лидирует версия, что «виноват» кэш процессора.
Т.е. случайный доступ к элементам большого массива на ~10% медленнее чем последовательный. Возможно и в правду какую-то роль может сыграть кэш. Однако, в исходной ситуации производительность проседала в разы. Значит есть еще что-то.
Я не понял, а где подсветка ASM для тега Source? Нету чтоль?Учитывая количество различных ассемблеров даже в пределах x86_64, ожидаемо, что её нет.
$ java -version
java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)
$ java App
0.039184857 2.360865017
0.038515955 1.953248084
0.033702157 1.955458985
0.033699063 1.953420415
0.03370587 1.952605481
0.033703395 1.956728721
0.033702775 1.954714283
0.033710201 1.954150574
0.033706178 1.95341268
0.033711439 1.952654055
$ java -XX:MaxTrivialSize=50 App
0.039914707 0.01686856
0.045489296 0.033697825
0.033701847 0.033747329
0.033702776 0.033704942
0.03370061 0.033698754
0.033699992 0.033697207
0.033698135 0.033700919
0.033698445 0.033698135
0.033698135 0.033699373
0.033708345 0.033699682
for(int i = 0; i < n; i++) {
int[] row = g[i];
for(int j = 0; j < n; j++) {
row[j] = i + j;
}
}
for(int i = 0; i < n; i++) {
g[0][i] = i;
}
for(int i = 1; i < n; i++) {
for(int j = 0; j < n; j++) {
g[i][j] = g[i-1][j]+1;
}
}
g: Array of Array of Integer;
…
n := 10000;
SetLength(g, n, n);
…
for i:=1 to n-1 do
for j:=1 to n-1 do
g[i,j] := i + j;
Знаете ли Вы массивы?