jAbLoK

blog už dávno nejen o javě

Java, I/O a performance?

17 komentářů

Vezměme si jednoduchý kousek kódu, který po řádcích čte data ze standardního vstupu a bez velkých cirátů je přeposílá na standardní výstup:

import java.io.*;
public class StreamEcho {
   public static void main(String[] args) throws Exception {
      BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
      for (String line = br.readLine(); line != null; line = br.readLine()) {
         System.out.println(line);
      }
   }
}

Teď si vezměme perlový ekvivalent:

#!/usr/bin/perl -w

use strict;

while (<STDIN>) {
   print;
}

A nakonec oběma verzemi prožeňte pár GB textových dat (data napřed něčím přečtěte jen tak, ať se v obou případech využívá disková cache). Taky vám perlová verze běží třikrát rychleji? Co s tím?

Aktualizace: podle komentářů důvodem bude hlavně konverze do Unicode a zpět, kterou se perlový kód narozdíl od Javy neobtěžuje (zmínili Zamboch a Petr Holík). Další rozdíl může být v tom, že System.out.println pokaždé provede flush (zmínil podlesh). Díky všem zúčastněným diskutérům!

Written by Pavel Kolesnikov

17 června, 2009 na 3:50 pm

Zasláno do Java

Tagged with , ,

17 komentářů

Subscribe to comments with RSS.

  1. String je obecne v jave hodne pomaly, ma vlastnost imutability, tzn. pokazde, kdyz se do Stringu neco nacte, tak se v pameti vytvori novy string (i kdyz stale nacitame do stejne promenne) a ten stary se necha v pameti jen tak lezet ladem. Pote narusta rezije s mazanim jiz nepouzivanych stringu, apod….

    resenim by bylo pouzit StringBuffer nebo StringBuilder, nicmene BufferReader vraci metodou readLine() String, takze bychom si moc nepomohli (i kdyz, kdo vi…)

    marty

    17 června, 2009 at 4:35 pm

    • Mozno trochu OT, ale…
      to nie je tak uplne pravda. Zalezi na tom ako sa String vytvara:
      String s1 = „str“;
      String s2 = „str“;
      V tomto pripade su identicke (==), pretoze sa pouzije ten isty String z ‚pamati‘, narozdiel od new String(„str“).

      ‚String je obecne v jave hodne pomaly‘ – to by som taktiez netvrdil. Mozno niekedy to tak bolo, ale v modernych JVM nie.

      Michal

      26 června, 2009 at 10:15 am

    • Pri stringu si treba dávať veľký pozor ešte na memory leaky. Takmer všetky frameworky, ktoré pracujú efektívne so stringami (StringUtils, klasická Java) často vytvárajú nové stringy tak, že ich vnútorná reprezentácia je odkazom na pole starého stringu.

      qedisk

      27 června, 2009 at 11:45 pm

  2. Myslim ze je to taky problem s encoding. InputStreamReader pouzije defaultni codepage OS. A potom kazdy znak prelozi do USC2 pro String. A pri zapisu znova do systemoveho.

    Myslim ze perl to bere jako ascii, nebo ne ?

    Zamboch

    17 června, 2009 at 9:02 pm

  3. Mozna jsem mimo, ale proc to jede pres ty bufferovane streamy kdyz se konce radku stejne nevyuzivaji? Jde o srovnani vykonnosti javy a perlu ci co?

    Nestaci simple presypavac v bytove podobe, navic pro 3GB dat? Neresi se zadne Stringy, zadne kodovani, zadna krec. Ale nevim, jestli to je rychlejsi, jen to tak predpokladam 🙂

    InputStream is = System.in;
    OutputStream out = System.out;
    byte[] buff = new byte[4096];
    int size = 0;
    while((size = is.read(buff)) > -1){
    out.write(buff, 0, size);
    }

    topolik

    18 června, 2009 at 3:19 pm

    • Topolik: po řádcích čtu proto, že jsem chtěl porovnávat stejné věci. Ber to tak, že to čtení po řádcích je součástí složitější aplikace, která zpracovává velké textové soubory.

      Pavel Kolesnikov

      18 června, 2009 at 5:00 pm

  4. A co takhle right tool for the right job 😉 Perl je humozní jazyk, ale na některé věci se hodí mnohem víc než Java.

    Tomáš Hubálek

    18 června, 2009 at 5:54 pm

    • Tomáši, tady jobem bylo „porovnat rychlost zpracovávání streamů po řádcích pomocí běžných prostředků Javy a Perlu“. Myslím, že se mi vhodné nástroje (tedy Javu a Perl) zvolit povedlo. 😉

      Pavel Kolesnikov

      19 června, 2009 at 9:07 am

  5. Vidím, že rozdíl pořád zůstává, ale zmenšuje se. V roce 2001 nebo 2002 jsem dělal stejné porovnání a perl vycházel zhruba 10x rychlejší.

    Wu

    18 června, 2009 at 11:11 pm

  6. Zakladni problem je ze BufferedReader parsuje UTF8. Jinak jde napsat vec ktera slape na paty i optimalizovanemu Ccku
    http://www.kotek.net/asynchttpd

    bubak

    26 června, 2009 at 11:00 am

  7. A co takhle:
    Scanner console = new Scanner(System.in);
    while (console.hasNextLine()) {
    System.out.println(console.nextLine());
    }

    Jiří Pejchal

    26 června, 2009 at 2:16 pm

    • Ani Scanner se na rychlost blížící se perlu nedostal.

      Pavel Kolesnikov

      29 června, 2009 at 9:02 pm

  8. Taky vidím trochu problém v tom BufferedReaderu. Zapsaný kód sice dokáže vykonávat ekvivalentní práci, nicméně není to to samé. Perlovský skutečně pouze čeká na znak konce řádky, vámi uvedený java kód toho dělá mnohem víc.

    Jerry!

    26 června, 2009 at 6:55 pm

  9. Dobry den, problem je v tom, ze kod ac vypada srovnatelne, srovnatelny neni. Perl ma znacne zjednodusenou praci. Prochazi STDIN stream a pokud narazi na \n jednoduse zapise vse od zacatku do vyskytu \n na vystup. A tak neustala dokola. Naproti tomu pouzity bufferedReader a reader provadi prekodovani vstupniho proudu bajtu z kodovani defaultniho na Vasi platforme do UTF-16 (2 bajty na znak). A pri zapisu do System.out coz je PrintStream se provadi opet konverze do defaultniho kodovani Vasi platformy. Dale se vytvari mnoho novy objektu typu String kam se KOPIRUJI jednotlive nacitane radky. V kodovani UTF-16. Tudiz to, ze tato implementace bezi 3x pomaleji paradoxne ukazuje spis na rychlost javy.

    Petr Holík

    2 července, 2009 at 5:12 pm

  10. Udelal jsem pokus s 1.1G txt filem obsahujicim par exotickych znaku (t.j. nejen ascii) a Java byla pomalejsi jen o 9 az 12%…

    konik

    20 července, 2009 at 12:27 pm

  11. Docela se divím, že zde nikdo nezmínil to nejdůležitější: System.out.println provádí
    pokaždé flush!

    podlesh

    10 srpna, 2009 at 9:14 am


Napsat komentář