unbuffered streams



  • Werner Salomon schrieb:

    .. da verstehe ich nicht, was Du damit sagen willst 😕

    Wenn ich dein Streambuf mit einer ungenerischen Ad-Hoc-Lösung vergleiche ist bei deine ungemein langsamer:

    void parse1(std::istreambuf_iterator<char> it, std::istreambuf_iterator<char> end,
                std::ostream& out, std::array<char, 64> const& arr)
    {
      out << "Format 1\n";
      std::ostreambuf_iterator<char> o(out);
      std::copy(arr.begin(), arr.end(), o);
      std::copy(++it, end, o);
    }
    
    void parse2(std::istreambuf_iterator<char> it, std::istreambuf_iterator<char> end,
                 std::ostream& out, std::array<char, 64> const& arr)
    {
      out << "Format 2\n";
      std::ostreambuf_iterator<char> o(out);
      std::copy(arr.begin(), arr.end(), o);
      std::copy(++it, end, o);
    }
    
    void parse(std::istream& in, std::ostream& out)
    {
      std::istreambuf_iterator<char> it(in), end;
      std::array<char, 64> save;
      std::copy_n(it, 64, save.begin());
      int magic = 17;
      for (int i=0; i<64; ++i)
        magic = 13*magic + save[i];
      if (magic%2)
        parse1(it, end, out, save);
      else
        parse2(in, end, out, save);
    }
    

    (das ist so in etwa, was ich von Meep² verstanden habe)

    Vollständiger Vergleich: http://ideone.com/Tl3y8K
    In meinen Messungen ergibt sich:

    # Ad-Hoc-Hack:
    real	0m0.168s
    user	0m0.000s
    sys 	0m0.304s
    
    # Reserve=1
    real	0m3.519s
    user	0m3.352s
    sys 	0m0.296s
    
    # Reserve=1<<16
    real    0m1.971s
    user    0m1.840s
    sys     0m0.252s
    

    Dass deine Variante so langsam ist, hätte ich nicht gedacht, vielleicht habe ich da etwas falsch gemacht.

    In diesem Fall wären -- wie auch hustbaer meint -- zwei Strategien angebracht, also ein "Streambuf [...] der selbständig die Strategie wechselt" (mein Post vorher).



  • werni schrieb:

    Dass deine Variante so langsam ist, hätte ich nicht gedacht, vielleicht habe ich da etwas falsch gemacht.

    Na ja - IMHO hast Du hier Äpfel mit Birnen verglichen. Das fängt schon damit an, dass Deine 'Ad-hoc-Lösung' keine Lösung ist. Zumindest hat der Anwender am Ende keinen Stream sondern ein Stück boost::array<64> plus einen Stream, wo er sich seine Sachen heraus pfrimeln darf. Stell Dir vor, da steht ab Position 62 bis Position 68 eine Zahl, die als solche geparst werden soll - das ist doch nur aufwendig. Diesen Aufwand hast Du nicht mit berechnet.
    Ansonsten parst Du ja gar nicht, sondern machst nur ein Byte-Copy nach cout.

    Ich habe mit selber so einen Test geschrieben, mit einem Buffer (im Memory!) mit 100kByte etwa zur Hälfte mit Text und zur anderen Hälfte mit Zahlen gefüllt. Wenn ich den BufferN<> zwischen istream und der eigentlichen Quelle setze, so verliert das Programm ca. 10% an Geschwindigkeit und absolut 1ms auf 100kByte. Dabei lese ich die Zahlen und überlese mit ignore die Texte. Wenn die Quelle jetzt eine Socket-Verbindung wäre, würde der relative Anteil noch weiter zurückgehen, da die Zeit für den Netz-Verkehr noch hinzukommt.

    Und wem diese 1ms immer noch zu viel Zeitverlust sind, der kann einfach nach dem (zweiten und endgültigem) Lesen der ersten 64-plus-ein-paar-Bytes den Streambuf wieder zurück setzen. Man muss nur aufpassen einen Zeitpunkt zu wählen, bei dem beide Streambufs (Wrapper und Quelle) synchron sind - sich also keine ungelesenen Bytes im Wrapper befinden, die der Quelle bereits entzogen wurden. Das kann man prüfen, indem man die noch ausstehenden Bytes abfragt.
    Etwa so:

    if( in.rdbuf()->in_avail() == 0 ) // in := istream; aktuell mit dem Wrapper
                {
                    in.rdbuf( &src ); // src := Quelle; streambuf umschalten
                }
    

    und mit dieser Methode lässt sich überhaupt kein Performanceunterschied mehr feststellen.

    Gruß
    Werner


Anmelden zum Antworten