2013-04-22 21 views
11
ChannelBufferInputStream responseStream = (ChannelBufferInputStream) response.getBodyAsStream(); 
ArrayList<Byte> arrayList = new ArrayList<Byte>(); 
try { 
    while (responseStream.available() > 0) { 
     arrayList.add(responseStream.readByte()); 
    } 
} catch (IOException e) { 
    e.printStackTrace(); 
    return internalServerError(); 
} 
Iterator<Byte> iterator = arrayList.iterator(); 
byte[] bytes = new byte[arrayList.size()]; 
int i = 0; 
while (iterator.hasNext()) { 
    bytes[i++] = iterator.next(); 
} 

Bu kod benim web uygulaması her sayfa yüklemesinde denir. Oldukça hızlı koşuyor gibi görünüyor, ama bu koşuyu daha hızlı hale getirebilecek bir şey var mı?InputStream byte [] içine dönüştürmenin en etkin yolu?

Düzenleme - bayt dizisi, çıkış akımına

ChannelBufferInputStream responseStream = (ChannelBufferInputStream) response.getBodyAsStream(); 
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 
try { 
    int read = responseStream.read(); 
    while (read != -1) { 
     byteArrayOutputStream.write(read); 
     read = responseStream.read(); 
    } 
} catch (IOException e) { 
    e.printStackTrace(); 
    return internalServerError(); 
} 
byte[] bytes = byteArrayOutputStream.toByteArray(); 
return ok(bytes).as(response.getHeader("Content-type")); 

düzenleme kullanılarak Güncelleme - Deney test kodu

ChannelBufferInputStream responseStream = (ChannelBufferInputStream) response.getBodyAsStream(); 
long t1 = System.nanoTime(); 

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 
try { 
    int read = responseStream.read(); 
    while (read != -1) { 
     byteArrayOutputStream.write(read); 
     read = responseStream.read(); 
    } 
} catch (IOException e) { 
    e.printStackTrace(); 
    return internalServerError(); 
} 
byte[] bytes = byteArrayOutputStream.toByteArray(); 

long t2 = System.nanoTime(); 
System.out.println(t2-t1); 
return ok(bytes).as(response.getHeader("Content-type")); 

Ortalama Zaman 100 + isteği sonra - 46873

ChannelBufferInputStream responseStream = (ChannelBufferInputStream) response.getBodyAsStream(); 
long t1 = System.nanoTime(); 

ArrayList<Byte> arrayList = new ArrayList<Byte>(); 
try { 
    while (responseStream.available() > 0) { 
     arrayList.add(responseStream.readByte()); 
    } 
} catch (IOException e) { 
    e.printStackTrace(); 
    return internalServerError(); 
} 
Iterator<Byte> iterator = arrayList.iterator(); 
byte[] bytes = new byte[arrayList.size()]; 
int i = 0; 
while (iterator.hasNext()) { 
    bytes[i++] = iterator.next(); 
} 

long t2 = System.nanoTime(); 
System.out.println(t2-t1); 
return ok(bytes).as(response.getHeader("Content-type")); 

Ortalama Zaman 100 sonra + istek - 522848

long t1 = System.nanoTime(); 
byte[] bytes; 
try { 
    bytes = org.apache.commons.io.IOUtils.toByteArray(responseStream); 
} catch (Exception e) { 
    return internalServerError(); 
} 

long t2 = System.nanoTime(); 
System.out.println(t2-t1); 

Ortalama Süre isteği 100+ sonra - 45088

long t1 = System.nanoTime(); 
byte[] bytes; 
try { 
    bytes = sun.misc.IOUtils.readFully(responseStream, -1, true); 
} catch (Exception e) { 
    return internalServerError(); 
} 

long t2 = System.nanoTime(); 
System.out.println(t2 - t1); 

Ortalama Süre isteği 100+ sonra - 20180

+0

Hey Matt, bu yazıyı okudum. Maksimum verim arıyorum. – sissonb

+0

Eğer bu konuda endişeleniyorsanız, farklı uygulamaları kendiniz ölçüp karşılaştırmalısınız. Ancak, "oldukça hızlı koşuyor gibi görünüyor" dediğinizden beri, kodunuzu daha hızlı çalıştırmaya çalışıyorsanız bu bir darboğaz gibi değil. –

+0

Bu http://stackoverflow.com/questions/6649100/cast-wrapper-array-to-corpanying-primitive-display –

cevap

12

Evet. Bir ArrayList yerine ByteArrayOutputStream kullanın. Ardından, InputStream öğesinden (hemen hemen hiç kullanılmayan available() kullanmadan) bayt parçalarını okuyun ve bu parçaları read() yöntemi -1 döndürene kadar ByteArrayOutputStream dosyasına yazın. Ardından, ByteArrayOutputStream numaralı telefondanByteArray() öğesine çağrı yapın.

Guava'nın ByteStreams.toByteArray() yöntemini kullanabilirsiniz, bu sizin için tüm bunları yapar veya kaynak kodunu okuyarak nasıl daha iyi bir fikir sahibi olabilirsiniz. IO tutorial'un okunması da yardımcı olabilir.

+0

Teşekkürler, test edeyim. Bazı testmark testleri de yapacağım – sissonb

+0

'available()', engellenmeden okunabilen bayt sayısını döndürür. Her zaman 0 döndürür (ve varsayılan olarak yapar). –

+0

@JBNizet teşekkürler. – Supericy

1

Neden? Bu kod, tüm veriler üzerinde iki ek kopya adımı olması dışında read(byte[])'a tamamen eşdeğerdir. Bunların hiçbirine ihtiyacınız yok. Basit bir read(byte[]), birkaç kat daha hızlı olacaktır.

available() kullanımı yanı geçersiz. Tüm engellemeye ihtiyacınız var, sadece engellemeden okunabilecek kısmı değil. Dönmen lazım. Apache Commons IO IOUtils.toByteArray yöntemle nesi var

+0

Teşekkürler, bu düzeltmeleri şimdi yapıyorum. Farkı birkaç dakika içinde göstereceğim. – sissonb

+0

Basit bir read(), (bu ChannelBufferInputStream uygulamasının bu garantiyi getirmediği sürece) tüm akışın okunduğunu garanti etmez. Belki de bu gerçekten kastettiğiniz şey değil, ancak -1 döndürülene kadar bir okuma döngüsüne ihtiyacınız var. –

+0

@JBNizet Anlaşıldı, açıklandı. – EJP

4

? Bu amaç için uzun yıllar boyunca optimize edildi.

+3

Hey, sadece bir işlev için bir kütüphane almak istemedim. – sissonb

+1

Eh, o kütüphanede zaman içinde daha fazla fonksiyon kullanacaksınız, ve zarar nedir? Her neyse, açık kaynak. Kaynağı okumak ve her şeyi istemiyorsan nasıl yaptığını gör. – bmargulies

+0

'sun.misc.IOUtils' kullanma hakkında ne düşünüyorsunuz? Java'ya yerleşik, ama güneş kütüphanelerine güvenmemeyi duydum. “IOUtils.readFully (responseStream, -1, true);” Ancak bu bana daha hızlı sonuçlar veriyor. Belki de vereceğim ve apache commons kullanacağım ... – sissonb

İlgili konular