Di Jawa, apa cara tercepat untuk mengulangi semua karakter dalam sebuah String, ini:
String str = "a really, really long string";
for (int i = 0, n = str.length(); i < n; i++) {
char c = str.charAt(i);
}
Atau ini:
char[] chars = str.toCharArray();
for (int i = 0, n = chars.length; i < n; i++) {
char c = chars[i];
}
EDIT:
Yang ingin saya ketahui adalah jika biaya berulang kali memanggil charAt
metode selama iterasi yang panjang berakhir menjadi kurang dari atau lebih besar dari biaya melakukan satu panggilan toCharArray
di awal dan kemudian secara langsung mengakses array selama iterasi.
Akan lebih bagus jika seseorang dapat memberikan tolok ukur yang kuat untuk panjang string yang berbeda, mengingat waktu pemanasan JIT, waktu memulai JVM, dll. Dan bukan hanya perbedaan antara dua panggilan System.currentTimeMillis()
.
for (char c : chars)
?charAt
menjadi kurang dari atau lebih besar dari biaya melakukan satu panggilan ketoCharArray
Jawaban:
PEMBARUAN PERTAMA: Sebelum Anda mencoba ini di lingkungan produksi (tidak disarankan), baca ini dulu: http://www.javaspecialists.eu/archive/Issue237.html Mulai dari Jawa 9, solusi seperti yang dijelaskan tidak akan berfungsi lagi , karena sekarang Java akan menyimpan string sebagai byte [] secara default.
UPDATE KEDUA: Pada 2016-10-25, pada AMDx64 8core saya dan sumber 1.8, tidak ada perbedaan antara menggunakan 'charAt' dan akses lapangan. Tampaknya jvm cukup optimal untuk menyejajarkan dan merampingkan panggilan 'string.charAt (n)'.
Itu semua tergantung pada lama
String
diperiksa. Jika, seperti yang dikatakan pertanyaan, itu untuk string panjang , cara tercepat untuk memeriksa string adalah dengan menggunakan refleksi untuk mengakses dukunganchar[]
dari string.Patokan acak lengkap dengan JDK 8 (win32 dan win64) pada 64 AMD Phenom II 4 core 955 @ 3,2 GHZ (dalam mode klien dan mode server) dengan 9 teknik berbeda (lihat di bawah!) Menunjukkan bahwa menggunakan
String.charAt(n)
adalah yang tercepat untuk kecil string dan menggunakanreflection
untuk mengakses array dukungan String hampir dua kali lebih cepat untuk string besar.PERCOBAAN
9 teknik optimasi yang berbeda dicoba.
Semua konten string diacak
Tes dilakukan untuk ukuran string dalam kelipatan dua mulai dengan 0,1,2,4,8,16 dll.
Pengujian dilakukan 1.000 kali per ukuran string
Tes dikocok secara acak setiap kali. Dengan kata lain, tes dilakukan secara acak setiap kali dilakukan, lebih dari 1000 kali lipat.
Seluruh rangkaian uji dilakukan ke depan, dan ke belakang, untuk menunjukkan efek pemanasan JVM pada optimasi dan waktu.
Seluruh rangkaian dilakukan dua kali, sekali dalam
-client
mode dan lainnya dalam-server
mode.KESIMPULAN
-client mode (32 bit)
Untuk string yang panjangnya 1 hingga 256 karakter , menelepon
string.charAt(i)
menang dengan pemrosesan rata-rata 13,4 juta hingga 588 juta karakter per detik.Juga, secara keseluruhan 5,5% lebih cepat (klien) dan 13,9% (server) seperti ini:
daripada seperti ini dengan variabel panjang akhir lokal:
Untuk string panjang, panjang 512 hingga 256 ribu karakter , menggunakan pantulan untuk mengakses array backing String paling cepat. Teknik ini hampir dua kali lebih cepat dari String.charAt (i) (178% lebih cepat). Kecepatan rata-rata pada kisaran ini adalah 1,111 miliar karakter per detik.
Field harus diperoleh sebelumnya dan kemudian dapat digunakan kembali di perpustakaan pada string yang berbeda. Menariknya, tidak seperti kode di atas, dengan akses Field, 9% lebih cepat untuk memiliki variabel panjang akhir lokal daripada menggunakan 'chars.length' dalam pemeriksaan loop. Inilah cara akses Field dapat diatur sebagai yang tercepat:
Komentar khusus pada mode -server
Akses lapangan mulai menang setelah string 32 karakter dalam mode server pada mesin Java 64 bit pada mesin AMD 64 saya. Itu tidak terlihat sampai panjang 512 karakter dalam mode klien.
Juga patut dicatat saya pikir, ketika saya menjalankan JDK 8 (build 32 bit) dalam mode server, kinerja keseluruhan 7% lebih lambat untuk string besar dan kecil. Ini adalah dengan membangun 121 Desember 2013 dari rilis awal JDK 8. Jadi, untuk saat ini, tampaknya mode server 32 bit lebih lambat daripada mode klien 32 bit.
Yang sedang berkata ... sepertinya satu-satunya mode server yang layak dipanggil adalah pada mesin 64 bit. Kalau tidak, itu justru menghambat kinerja.
Untuk build 32 bit berjalan
-server mode
pada AMD64, saya bisa mengatakan ini:Layak juga dikatakan, String.chars () (Streaming dan versi paralel) adalah bust. Cara lebih lambat dari cara lainnya. The
Streams
API adalah cara yang agak lambat untuk melakukan operasi string umum.Daftar Keinginan
Java String dapat memiliki predikat menerima metode yang dioptimalkan seperti berisi (predikat), forEach (konsumen), forEachWithIndex (konsumen). Dengan demikian, tanpa perlu bagi pengguna untuk mengetahui panjang atau mengulangi panggilan ke metode String, ini bisa membantu mem-parsing perpustakaan
beep-beep beep
mempercepat.Teruslah bermimpi :)
Happy Strings!
~ SH
Pengujian ini menggunakan 9 metode pengujian string berikut untuk keberadaan spasi putih:
"charAt1" - PERIKSA ISI STRING, CARA BIASA:
"charAt2" - SAMA SAJA DI ATAS TAPI MENGGUNAKAN String.length () BUKAN PEMBUATAN LOKAL FINAL int UNTUK PANJANG
"stream" - GUNAKANStreaming String JAVA-8 BARU DAN LULUSKAN PREDIKASI UNTUK MELAKUKAN PEMERIKSAAN
"streamPara" - SAMA SEKALI DI ATAS, TAPI OH-LA-LA - GO PARALLEL !!!
"reuse" - REFILL A char REUSABLE [] DENGAN ISI STRING
"new1" - MENDAPATKAN SALINAN BARU DARI char [] DARI STRING
"new2" - SAMA SEKALI DI ATAS, TETAPI GUNAKAN "FOR-SETIAP"
"field1" - FANCY !! OBTAIN FIELD FOR ACCESS TO THE INTERNAL char char []
"field2" - SAMA SEKALI DI ATAS, TETAPI GUNAKAN "FOR-SETIAP"
HASIL KOMPOSIT UNTUK
-client
MODE KLIEN (gabungan tes maju dan mundur)Catatan: bahwa mode -client dengan Java 32 bit dan -server mode dengan Java 64 bit sama seperti di bawah ini pada mesin AMD64 saya.
HASIL KOMPOSIT UNTUK
-server
MODE SERVER (gabungan tes maju dan mundur)Catatan: ini adalah tes untuk Java 32 bit yang berjalan dalam mode server pada AMD64. Mode server untuk Java 64 bit sama dengan Java 32 bit dalam mode klien kecuali bahwa akses Field mulai menang setelah ukuran 32 karakter.
KODE PROGRAM YANG DAPAT DILAKUKAN
(untuk menguji pada Java 7 dan sebelumnya, hapus dua tes aliran)
sumber
Ini hanya optimasi mikro yang tidak perlu Anda khawatirkan.
mengembalikan Anda salinan
str
array karakter (dalam JDK, ia mengembalikan salinan karakter dengan meneleponSystem.arrayCopy
).Selain itu,
str.charAt()
hanya memeriksa apakah indeks memang dalam batas dan mengembalikan karakter dalam indeks array.Yang pertama tidak membuat memori tambahan di JVM.
sumber
Hanya untuk rasa ingin tahu dan untuk membandingkan dengan jawaban Saint Hill.
Jika Anda perlu memproses data berat Anda tidak boleh menggunakan JVM dalam mode klien. Mode klien tidak dibuat untuk optimisasi.
Mari kita bandingkan hasil tolok ukur @Saint Hill menggunakan JVM dalam mode Klien dan mode Server.
Lihat juga: Perbedaan nyata antara "java -server" dan "java -client"?
MODE KLIEN:
MODE SERVER:
KESIMPULAN:
Seperti yang Anda lihat, mode server jauh lebih cepat.
sumber
Penggunaan pertama
str.charAt
harus lebih cepat.Jika Anda menggali di dalam kode sumber
String
kelas, kita bisa melihatnyacharAt
diimplementasikan sebagai berikut:Di sini, yang dilakukannya hanyalah mengindeks array dan mengembalikan nilainya.
Sekarang, jika kita melihat implementasi dari
toCharArray
, kita akan menemukan di bawah ini:Seperti yang Anda lihat, itu melakukan
System.arraycopy
yang pasti akan sedikit lebih lambat daripada tidak melakukannya.sumber
Terlepas dari jawaban @Saint Hill jika Anda mempertimbangkan kompleksitas waktu str.toCharArray () ,
yang pertama lebih cepat bahkan untuk string yang sangat besar. Anda dapat menjalankan kode di bawah ini untuk melihatnya sendiri.
keluaran:
sumber
Sepertinya niether lebih cepat atau lebih lambat
Untuk string panjang saya akan memilih yang pertama. Mengapa menyalin string panjang? Dokumentasi mengatakan:
// Edit 1
Saya telah mengubah tes untuk mengelabui optimasi JIT.
// Edit 2
Ulangi tes 10 kali untuk membiarkan JVM memanas.
// Edit 3
Kesimpulan:
Pertama-tama
str.toCharArray();
menyalin seluruh string dalam memori. Ini bisa memakan memori untuk string panjang. MetodeString.charAt( )
mencari char in char array di dalam indeks pemeriksaan kelas String sebelumnya. Sepertinya metode Strings first yang cukup pendek (yaituchatAt
metode) sedikit lebih lambat karena pemeriksaan indeks ini. Tetapi jika String cukup panjang, menyalin seluruh array char menjadi lebih lambat, dan metode pertama lebih cepat. Semakin panjang string, semakin lambattoCharArray
kinerjanya. Cobalah untuk mengubah batas dalamfor(int j = 0; j < 10000; j++)
lingkaran untuk melihatnya. Jika kita membiarkan kode pemanasan JVM berjalan lebih cepat, tetapi proporsinya sama.Lagi pula itu hanya optimasi mikro.
sumber
for:in
opsi, hanya untuk bersenang-senang?Iterable
atau array.String.toCharArray()
membuat array char baru, berarti alokasi memori dengan panjang string, kemudian menyalin array char string asli menggunakanSystem.arraycopy()
dan kemudian mengembalikan salinan ini ke pemanggil. String.charAt () mengembalikan karakter pada posisii
dari salinan asli, itu sebabnyaString.charAt()
akan lebih cepat daripadaString.toCharArray()
. Meskipun,String.toCharArray()
mengembalikan salinan dan bukan char dari array String asli, di manaString.charAt()
mengembalikan karakter dari array char asli. Kode di bawah ini mengembalikan nilai pada indeks yang ditentukan dari string ini.kode di bawah ini mengembalikan array karakter yang baru dialokasikan yang panjangnya adalah panjang dari string ini
sumber
Yang kedua menyebabkan array char baru untuk dibuat, dan semua karakter dari String yang akan disalin ke array char baru ini, jadi saya kira yang pertama lebih cepat (dan kurang haus memori).
sumber