web-dev-qa-db-fra.com

Le moyen le plus rapide pour lire ligne par ligne STDIN?

Je suis à la recherche de la méthode la plus efficace pour lire ligne par ligne STDIN.

La première ligne est le nombre de conditions à tester. Toutes les lignes suivantes sont des conditions (chaînes) avec un maximum de 100 000 caractères.

J'ai déjà essayé ce qui suit (plus le résultat pour 4 fois 90 000 caractères:

  • Scanner avec boucle while (7255 ms)

    Scanner sc = new Scanner(System.in);
    int numberOfLines = Integer.parseInt(sc.nextLine());
    long start = 0;
    int i = 1;
    while (i<=numberOfLines){
        start = System.currentTimeMillis();
        sc.nextLine();
        Debug.println((System.currentTimeMillis()-start) + "ms for scanner while");
        i++;
    }
    
    • Résultats :
      1. 3228 ms pour le scanner pendant
      2. 2264 ms pour le scanner pendant
      3. 1309 ms pour le scanner pendant
      4. 454 ms pour le scanner pendant
  • Scanner avec une boucle for (7078 ms)

    Scanner sc = new Scanner(System.in);
    int numberOfLines = Integer.parseInt(sc.nextLine());
    long start = 0;
    for (int i = 1; i<= numberOfLines;i++){
        start = System.currentTimeMillis();
        sc.nextLine();
        Debug.println((System.currentTimeMillis()-start) + "ms for scanner for");
        //i++;     
    }
    
    • Résultats :
      1. 3168 ms pour scanner pour
      2. 2207ms pour scanner pour
      3. 1236ms pour scanner pour
      4. 467 ms pour scanner pour
  • BufferedReader avec une boucle for (7403 ms)

    try {
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    
    int numberOfLines = Integer.parseInt(br.readLine());
    long start = 0;
    for (int i = 0; i< numberOfLines;i++){
        start = System.currentTimeMillis();
        br.readLine();
        Debug.println((System.currentTimeMillis()-start) + "ms for bufferreader for");
        //i++;
    }
     } catch (Exception e) {
    System.err.println("Error:" + e.getMessage());
    

    }

    • Résultats :
      1. 3273ms pour le lecteur de tampons pour
      2. 2330ms pour le lecteur de tampons pour
      3. 1293ms pour le lecteur de tampons pour
      4. 507 ms pour le lecteur de tampons pour
  • BufferedReader avec une boucle while (7461 ms)

    try {
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    
    int numberOfLines = Integer.parseInt(br.readLine());
    int i=0;
    long start = 0;
    while(i< numberOfLines){
        start = System.currentTimeMillis();
        br.readLine();
        Debug.println((System.currentTimeMillis()-start) + "ms for bufferreader while");
        i++;
    }
     } catch (Exception e) {
    System.err.println("Error:" + e.getMessage());
    

    }

    • Résultats :
      1. 3296 ms pour le lecteur de mémoire tampon pendant
      2. 2358 ms pour le lecteur de mémoire tampon pendant
      3. 1307 ms pour le lecteur de mémoire tampon pendant
      4. 500 ms pour le lecteur de tampons pendant

Lors du débogage du temps pris, j'ai remarqué que le temps pris diminue après chaque lecture. Est-il possible de restreindre les octets qui sont initialisés (par exemple: si vous avez un maximum de 100 000 caractères, limitez le scanner/tampon de lecture à initialiser uniquement 100 000 caractères. Après une lecture, il devra se recharger avec les 100 000 caractères suivants)

Toutes les idées à ce sujet sont les bienvenues.

EDIT: Ajout du code pour chaque scénario avec le temps pris par ligne lue. Également changé de 100 000 à 100 000 pour lire plus facilement.

20
Maarten Kesselaers

Regardé à l'intérieur BufferedReader#readLine la source. Il y a plusieurs problèmes que je vois:

  1. Il utilise StringBuffer au lieu de StringBuilder, ce qui crée une surcharge de synchronisation.
  2. Il semble également y avoir des frais de copie de données - pas entièrement sûr, mieux vaut le vérifier.
  3. Objet moniteur dédié dans le BufferedReader et encore plus de surcharge de synchronisation.

Vous pouvez tenter votre chance avec deux choses:

  1. Écrire votre propre mise en mémoire tampon, ce qui pourrait vous faire gagner du temps lors de la double copie des données.
  2. Écrire votre propre méthode nextLine qui utiliserait StringBuilder et passerait en revue les données source avec un cycle simple.
5
Andrei LED