String
Java'da a'dan yazdırılamayan tüm karakterleri çıkarmanın en hızlı yolu nedir ?
Şimdiye kadar 138 bayt, 131 karakterlik String üzerinde denedim ve ölçtüm:
- String'ler
replaceAll()
- en yavaş yöntem- 517009 sonuç / sn
- Bir Kalıbı önceden derleyin, ardından Eşleştiriciyi kullanın
replaceAll()
- 637836 sonuç / sn
- StringBuffer kullanın,
codepointAt()
tek tek kullanarak kod noktalarını alın ve StringBuffer'a ekleyin- 711946 sonuç / sn
- StringBuffer kullanın,
charAt()
tek tek kullanarak karakterleri alın ve StringBuffer'a ekleyin- 1052964 sonuç / sn
- Bir
char[]
tamponu önceden tahsis edin ,charAt()
tek tek kullanarak karakterleri alın ve bu tamponu doldurun, ardından tekrar String'e dönüştürün- 2022653 sonuç / sn
- 2
char[]
arabelleği önceden tahsis et - eski ve yeni, kullanarak mevcut String için tüm karakterleri bir kerede alıngetChars()
, eski arabelleği tek tek yineleyin ve yeni arabelleği doldurun, ardından yeni arabelleği String'e dönüştürün - kendi en hızlı sürümüm- 2502502 sonuç / sn
- Sadece kullanarak - 2 tamponlarla aynı malzeme
byte[]
,getBytes()
ve "UTF-8" olarak kodlama belirten- 857485 sonuç / sn
- 2
byte[]
arabellekle aynı şeyler , ancak kodlamayı sabit olarak belirlemeCharset.forName("utf-8")
- 791076 sonuç / sn
- 2
byte[]
arabellekle aynı şeyler , ancak kodlamayı 1 baytlık yerel kodlama olarak belirleme (yapılacak çok az mantıklı bir şey)- 370164 sonuç / sn
En iyi denemem şuydu:
char[] oldChars = new char[s.length()];
s.getChars(0, s.length(), oldChars, 0);
char[] newChars = new char[s.length()];
int newLen = 0;
for (int j = 0; j < s.length(); j++) {
char ch = oldChars[j];
if (ch >= ' ') {
newChars[newLen] = ch;
newLen++;
}
}
s = new String(newChars, 0, newLen);
Nasıl daha hızlı hale getirileceğine dair herhangi bir fikrin var mı?
Çok garip bir soruyu yanıtlamak için bonus puanlar: Neden "utf-8" karakter kümesi adını doğrudan kullanmak, önceden tahsis edilmiş statik sabit kullanmaktan daha iyi performans sağlar Charset.forName("utf-8")
?
Güncelleme
- Cırcır ucubesinden gelen öneri, etkileyici 3105590 sonuç / saniye performansı, +% 24'lük bir iyileşme sağlar!
- Dan Öneri Ed Staub 3471017 sonuçlar / sn, önceki en fazla + 12% - Yine başka bir gelişme elde edilir.
Güncelleme 2
Önerilen tüm çözümleri ve bunların çapraz mutasyonlarını toplamak için elimden gelenin en iyisini yaptım ve github'da küçük bir kıyaslama çerçevesi olarak yayınladım . Şu anda 17 algoritma kullanıyor. Bunlardan biri "özel" - Voo1 algoritması ( SO kullanıcısı Voo tarafından sağlanır ) karmaşık yansıma hileleri kullanır, böylece yıldız hızları elde eder, ancak JVM dizgilerinin durumunu bozar , bu nedenle ayrı olarak değerlendirilir.
Kutunuzdaki sonuçları belirlemek için kontrol edebilir ve çalıştırabilirsiniz. İşte benimki ile ilgili aldığım sonuçların bir özeti. Özellikleri:
- Debian sid
- Linux 2.6.39-2-amd64 (x86_64)
- Bir paketten yüklenen Java
sun-java6-jdk-6.24-1
, JVM kendini şu şekilde tanımlar:- Java (TM) SE Çalışma Zamanı Ortamı (derleme 1.6.0_24-b07)
- Java HotSpot (TM) 64-Bit Sunucu VM (yapı 19.1-b02, karma mod)
Farklı algoritmalar, farklı bir girdi verisi kümesi verildiğinde sonuçta farklı sonuçlar gösterir. 3 modda bir kıyaslama yaptım:
Aynı tek dize
Bu mod, StringSource
sınıf tarafından bir sabit olarak sağlanan aynı tek dizede çalışır . Hesaplaşma:
İşlem / s │ Algoritması ──────────┼────────────────────────────── 6535947 │ Voo1 ──────────┼────────────────────────────── 5350454 │ RatchetFreak2EdStaub1GreyCat1 5 249 343 │ EdStaub1 5002501 │ EdStaub1GreyCat1 4 859086 │ ArrayOfCharFromStringCharAt 4295532 │ RatchetFreak1 4045 307 │ ArrayOfCharFromArrayOfChar 2790178 │ RatchetFreak2EdStaub1GreyCat2 2583 311 │ RatchetFreak2 1274 859 │ StringBuilderChar 1138174 │ StringBuilderCodePoint 994 727 │ ArrayOfByteUTF8String 918611 │ ArrayOfByteUTF8Const 756086 │ Eşleştirici 598945 │ StringReplaceAll 46045 │ ArrayOfByteWindows1251
Çizelge halinde:
(kaynak: greycat.ru )
Çoklu dizeler, dizelerin% 100'ü kontrol karakterleri içerir
Kaynak dizge sağlayıcısı (0..127) karakter kümesi kullanarak çok sayıda rastgele dizeyi önceden oluşturdu - bu nedenle neredeyse tüm dizeler en az bir kontrol karakteri içeriyordu. Algoritmalar, bu önceden oluşturulmuş diziden sıralı dizilerle dizeler aldı.
İşlem / s │ Algoritması ──────────┼────────────────────────────── 2 123142 │ Voo1 ──────────┼────────────────────────────── 1782 214 │ EdStaub1 1776199 │ EdStaub1GreyCat1 1694 628 │ ArrayOfCharFromStringCharAt 1 481 481 │ ArrayOfCharFromArrayOfChar 1460 067 │ RatchetFreak2EdStaub1GreyCat1 1438435 │ RatchetFreak2EdStaub1GreyCat2 1 366 494 │ RatchetFreak2 1349710 │ RatchetFreak1 893 176 │ ArrayOfByteUTF8String 817 127 │ ArrayOfByteUTF8Const 778 089 │ StringBuilderChar 734 754 │ StringBuilderCodePoint 377 829 │ ArrayOfByteWindows1251 224 140 │ Eşleştirici 211 104 │ StringReplaceAll
Çizelge halinde:
(kaynak: greycat.ru )
Çoklu dizeler, dizelerin% 1'i kontrol karakterleri içerir
Öncekiyle aynı, ancak dizelerin yalnızca% 1'i kontrol karakterleriyle oluşturuldu - diğer% 99'u [32..127] karakter seti kullanılarak oluşturuldu, bu nedenle hiçbir kontrol karakterleri içeremezler. Bu sentetik yük, benim yerime bu algoritmanın gerçek dünya uygulamasına en yakın olanıdır.
İşlem / s │ Algoritması ──────────┼────────────────────────────── 3711 952 │ Voo1 ──────────┼────────────────────────────── 2 851440 │ EdStaub1GreyCat1 2455796 │ EdStaub1 2426007 │ ArrayOfCharFromStringCharAt 2347969 │ RatchetFreak2EdStaub1GreyCat2 2 242152 │ RatchetFreak1 2171 553 │ ArrayOfCharFromArrayOfChar 1922707 │ RatchetFreak2EdStaub1GreyCat1 1857 010 │ RatchetFreak2 1023751 │ ArrayOfByteUTF8String 939 055 │ StringBuilderChar 907 194 │ ArrayOfByteUTF8Const 841 963 │ StringBuilderCodePoint 606465 │ Eşleştirici 501 555 │ StringReplaceAll 381 185 │ ArrayOfByteWindows1251
Çizelge halinde:
(kaynak: greycat.ru )
En iyi cevabı kimin verdiğine karar vermek benim için çok zor, ancak gerçek dünyadaki en iyi çözümün Ed Staub tarafından verildiği / esinlendiği düşünüldüğünde, sanırım cevabını not etmek adil olur. Bunda yer alan herkese teşekkürler, görüşleriniz çok yardımcı ve paha biçilemezdi. Kutunuzda test paketini çalıştırmaktan ve daha iyi çözümler önermekten çekinmeyin (çalışan JNI çözümü, kimse var mı?).
Referanslar
- Karşılaştırma paketi içeren GitHub deposu