Java’da Performans Arttırıcı Yollar - Bölüm 3
8 Ocak 2006 tarihli, Java, Programlama köşesine ait yazı.
Java’da performans arttırıcı yollar yazı dizisinin 3. bölümünde input/output konusuna değiniyoruz. Serinin ilk iki yazısı olan giriş yazısını ve string yazısını okumanızı tavsiye ederim.
5. Input/Output
Java uygulamalarının temel parçalarından biri olan input/output konusunda performans arttırmak için bazı teknikleri tanıtacağız.
5.1 Buffering
Tabii ki dosya okuma veya yazma işleminde performası en fazla arttıracak etken buffering, yani input veya output işleminin büyük parçalar halinde yapılmasıdır. Her seferinde bir byte okumak yerine buffering yapmanın yararı aşağıda gösteriliyor:
int cnt = 0;
int c;
/* tek byte */
while ((c = fis.read()) != -1)
if (c == ‘x’)
cnt++;
fis.close();
/* buffering */
fis = new FileInputStream(args[0]);
byte buf[] = new byte[1024];
cnt=0;
int n;
while ((n = fis.read(buf)) > 0)
for(int i=0;i<n; i++)
if (buf[i] == ‘x’)
cnt++;
Üstteki program parçası bir dosyadaki ‘x’ karakterleri sayısını bulmak için iki farklı yöntem kullanıyor: ilkinde her karakteri teker teker alırken ikincisinde 1024 byte’lık bölümler halinde alıp kontrol ediyor. Buffering kullanılarak yapılan işlem diğer işleme göre 20 kat hızlı tamamlanmış. Her ne kadar read() metodu java.io.FileInputStream içerisinde native olarak ifade edilse de buffering kullanılmadığında, read() metodunun her çağırılışındaki performans kaybı en büyük dezavantaj oluyor.
5.2 BufferedReader
java.io içerisinde bulunan class’lar katman mantığıyla organize edilmiştir; şöyle ki, bir I/O katmanı diğer bir katman üzerine eklenerek artı özellikler kazanabilir. Bu esneklik input/output işlemlerini daha verimli yapmamıza olanak sağlar. Neden olduğunu aşağıdaki örnekle anlayabilirsiniz:
Reader r = new FileReader(args[0]);
int c;
while ((c = r.read()) != -1);
r.close();
/* buffering kullanılarak */
r = new FileReader(args[0]);
r = new BufferedReader(r);
while ((c = r.read()) != -1);
r.close();
while loop’ların dummy (yani birşey yapmadan) döndüklerine dikkat edin. İlk kısımda yalnızca FileReader kullanarak dosyayı okurken, ikinci kısımda aynı FileReader‘ı kullanarak bir BufferedReader oluşturuyoruz. İkinci kısmın ilk kısma göre 4 kat hızlı çalışıyor. Bunun nedeni BufferedReader‘ın verileri büyük parçalar halinde belleğe alıp teker teker yollamasından kaynaklanıyor.
5.3 Biçimleme
Şimdiye kadar veriyi okuma ve yazma konusuna ve nasıl performansını arttırabileceğimize odaklandık. Ancak bu verileri diske yazmak veya ağ üzerinde göndermek için nasıl biçimleyeceğimize değinmedik. Tabii ki biçimleme konusunda da farklı yaklaşımlar var. Test etmek için yapmamız gerek aynı sonucu veren farklı yolları deneyip hangisinin daha verimli çalıştığını bulmak. Örnek olarak programımızdan aşağıdaki gibi bir çıktı istiyoruz:
The square of 6 is 36
…
İlk kullanacağımız teknik tabii ki en kolay teknik olacaktır:
public class io_msg1 {
public static void main(String args[]) {
final int N = 25000;
String s;
for(int i=1;i<=N; i++)
s = “The square of”+i+”is”+(i*i);
}
}
İkinci yol önceden oluşturulmuş bir java.text.MessageFormat ile olacak:
import java.text.*;
public class io_msg2 {
public static void main(String args[]) {
final int N = 25000;
Object argvec[] = new Object[2];
MessageFormat f = new MessageFormat(”The square of {0,number,#} is {1,number,#}”);
for(int i=1;i<=N; i++) {
argvec[0] = new Integer(i);
argvec[1] = new Integer(i * i);
String s = f.format(argvec);
}
}
}
Son yol ise bir öncekinin derlenmemiş hali, yani MessageFormat class’ının static bir metodunu kullanarak olacak:
import java.text.*;
public class io_msg3 {
public static void main(String args[]) {
final int N = 25000;
Object argvec[] = new Object[2];
String f = “The square of {0,number,#} is {1,number,#}”;
for(int i=1;i<=N; i++) {
argvec[0] = new Integer(i);
argvec[1] = new Integer(i * i);
String s = MessageFormat.format(f, argvec);
}
}
}
Şimdi sonuçlara bir bakalım:
#2 12027
#3 41409
Sonuçlara göre ilk yol sonuncuya göre ~20 kat daha hızlı çalışıyor. Tabii ki bu MessageFormat aracını kullanmamanız gerektiği anlamına gelmez, MessageFormat programınızı uluslararası dillere uyumlu yazıyorsanız (i18n) çok kullanışlı bir araçtır, ancak ne kadar verimli çalıştığını da akıldan çıkarmamak lazım.
5.4 Dosya Bilgisine Erişim
Özellikle veri dosyalarıyla çalışıyorsanız, diğer programlama dilleri gibi Java kütüphaneleri de işletim sisteminin bazı özelliklerini gerektiğinde kullanır. Örnek olarak bir dosyanın uzunluğunu gösteren aşağıdaki koda bakalım:
public class io_length {
public static void main(String args[]) {
long len = new File(args[0]).length();
System.out.println(len);
}
}
Program gördüğünüz gibi File.length() metodunu çağırıyor. length() metodu dosyanın uzunluğunu bilmediğinden işletim sisteminden yardım istiyor ve dosyanın uzunluğu, klasör olup olmadığı, salt okunurluk/gizlilik gibi özelliklerine erişebiliyor. Bu işlemin çok hızlı çalışan bir işlem olmadığını bilmek gerekli. Yani bir dosyanın uzunluğunu zaten elinizde varsa ve kısa bir süre içinde değişebileceğinden emin değilseniz birkaç satır aşağıda tekrar almaya çalışmayın.
Yorumlar - Başa Dön
8 Aralık 2007
mesela “ankara” kelimesini nasıl harf harf alırız onu anlamadım?