bufferedWriter



  • hi,
    bitte um feedback zu meinem BufferedWriter implementierung.
    eignet sich ein vector<char> hier, wenn ich strings schreibe?
    anstatt die chars einzeln zu kopieren, kann man eventuell memcopy nehmen?
    LG

    #include <iostream>
    #include <vector>
    #include <string>
    using namespace std;
    
    std::ostream& operator << (std::ostream& os, const std::vector<char>& v) 
    {
        os << "[";
        for (typename std::vector<char>::const_iterator ii = v.begin(); ii != v.end(); ++ii)
        {
            os << *ii;
        }
        os << "]";
        return os;
    }
    
    class BufferedWrite {
    private:
    	const unsigned int buffer_size;
    	vector<char> buffer;
    	unsigned int curr_index;
    
    	void flush() {
    		cout << buffer << endl;
    	}
    
    public:
    	BufferedWrite(unsigned int buffer_size_): buffer(buffer_size_, 0), 
     						                      buffer_size(buffer_size_),
     						                      curr_index(0) {}
    
    	void write(const string &str) {
    		unsigned int i = 0;
    
    		while (i < str.size()) {
    			buffer[curr_index] = str[i];
    			curr_index++;
    			i++;
    
    			if (curr_index == buffer_size) {
    				flush();
    				curr_index = 0;
    			}
    		} 
    	}
    };
    
    int main() {
    	BufferedWrite w(10);
    	w.write("hello");
    	w.write("du");
    	w.write("wiegehts");
    
    	return 0;
    }
    


  • Miss es doch einfach mal.

    Generierst dir en paar Random Strings und gibst die einmal mit deinem Writer und einmal stupide mit std::cout aus. Mal sehen was dann schneller ist.



  • zwischen vector<char> und string ist kaum ein performance unterschied...
    memcpy jedoch improved den speed.

    #include <iostream>
    #include <vector>
    #include <string>
    #include <cstring>
    #include <chrono>
    #include <array>
    using namespace std;
    
    #define BENCHMARKING
    const int test_len = 1000;
    
    std::ostream& operator << (std::ostream& os, const std::vector<char>& v) 
    {
        os << "[";
        for (typename std::vector<char>::const_iterator ii = v.begin(); ii != v.end(); ++ii)
        {
            os << *ii;
        }
        os << "]";
        return os;
    }
    
    class BufferedWrite {
    private:
    	const unsigned int buffer_size;
    	vector<char> buffer;
    	unsigned int buffer_index;
    
    	void flush() {
    		//cout << buffer << endl;
    		buffer_index = 0;
    	}
    
    public:
    	BufferedWrite(unsigned int buffer_size_): buffer(buffer_size_, 0), 
     						                      buffer_size(buffer_size_),
     						                      buffer_index(0) {}
    
    	void write(const string &str) {
    		unsigned int bytes_to_copy = str.size();
    		unsigned int copy_index = 0;
    
    		while (bytes_to_copy > 0) {
    			unsigned int size = 0;
    			unsigned int free_space = buffer_size - buffer_index;
    
    			if (bytes_to_copy >= free_space) {
    				size = free_space;
    			} 
    			else {
    				size = bytes_to_copy;
    			}
    
    			memcpy(&buffer[buffer_index], (char*)(&str[copy_index]), size);
    
    			buffer_index += size;
    			copy_index += size;
    			bytes_to_copy -= size;
    
    			if (buffer_index == buffer_size) {
    				flush();
    			}
    		}
    	}
    };
    
    class random_text_generator {
    public:
        random_text_generator(const std::string& str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
        : m_str(str) {
            std::srand(std::time(0));
        }   
    
        std::string operator ()(std::size_t min_len, std::size_t max_len) {
            std::size_t len = min_len + rand() % (max_len - min_len);
            std::string seq;
            std::size_t siz = m_str.size();
    
            if(siz) {
                while(len--) {
                    seq.push_back(m_str[rand() % siz]);
                }
            }
    
            return seq;
        }
    
    private:        
        std::string m_str;
    };
    
    int main() {
    	BufferedWrite w(1024);
    	random_text_generator rtg;
    	vector<string> string_vec(test_len);
    
    	for (int i = 0; i < test_len; i++) {
    		string_vec[i] = rtg(100, 200);
    	}
    
    #ifdef BENCHMARKING
        auto start = std::chrono::steady_clock::now();
    #endif
    
    	for (int i = 0; i < test_len; i++) {
    		w.write(string_vec[i]);
    	}
    
    #ifdef BENCHMARKING
        auto end = std::chrono::steady_clock::now();
        auto diff = end - start; 
        std::cout << "\nbenchmark: " << std::chrono::duration <double, std::milli> (diff).count() << "\n\n";
    #endif	
    
    	return 0;
    }
    


  • Ein buffered Writer auf std::iostream macht keinen Sinn, da std::iostream bereits gepuffert ist.



  • tntnet...das war ja nur um den string auszugeben fuers debuging....

    das eigentlich flush soll ueber das netzwerk passieren...

    was mache ich wenn der buffer voll ist und und die write funktion noch einmal geschrieben wird?

    was will der interviewer eigentlich rausfinden, wenn er dich einen bufferedwriter implementieren laesst?



  • hackglobal schrieb:

    was mache ich wenn der buffer voll ist und und die write funktion noch einmal geschrieben wird?

    Die Daten auf/in die "Sink" schreiben?

    hackglobal schrieb:

    was will der interviewer eigentlich rausfinden, wenn er dich einen bufferedwriter implementieren laesst?

    Ob der Kandidat überhaupt programmieren kann.
    Ob der Kandidat eine relativ einfache Vorgabe fehlerfrei implementieren kann.
    Ob der Kandidat von der Form her halbwegs sauberen, lesbaren Code schreiben kann.
    Ob der Kandidat dazu neigt Dinge unnötig kompliziert zu machen.
    Ob der Kandidat dazu neigt Dinge zu einfach zu machen.
    Ob der Kandidat die Standard-Library kennt und verwendet.

    Evtl. auch ob der Kandidat schlau genug gleich nachzufragen welche Art von Daten der Buffered-Writer überhaupt buffern soll, welches Interface dieser Buffered Writer zur Verfügung stellen muss, welches er vom seiner "Sink" verlangen darf/soll etc.



  • hackglobal schrieb:

    zwischen vector<char> und string ist kaum ein performance unterschied...
    memcpy jedoch improved den speed.

    Den Grossteil des memcpy -Vorteils wird nicht memcpy selbst ausmachen, sondern dass du jetzt eine "schlauere" (dafür auch kompliziertere) Kopierschleife hast.
    Statt memcpy könntest du dann vermutlich genau so gut auch std::copy oder - je nach Compiler - auch gleich eine selbstgeschriebene Schleife nehmen.



  • Die Daten auf/in die "Sink" schreiben?

    ja, die sink ist eine TCP verbindung... dh der buffer muesste fuer die zeit blockiert werden...

    kann ich eine art double buffer bauen, falls waehrend dem senden ueber tcp dei write funktion noch einmal aufgerufen wird?



  • mit std::copy wuerde das dann wie folgt aussehen?

    std::copy(str.begin()+copy_index, str.begin()+copy_index+size, buffer.begin()+buffer_index);
    

    was ist der vorteil von std::copy?



  • was ich so sehe ist memcpy schneller als std::copy! stimmt das? warum soll man dann std::copy nehmen?


  • Mod

    hackglobal schrieb:

    kann ich eine art double buffer bauen, falls waehrend dem senden ueber tcp dei write funktion noch einmal aufgerufen wird?

    Möglich ist das. Ob du das machen kannst, kannst am besten du selbst beantworten.

    hackglobal schrieb:

    was ist der vorteil von std::copy?

    Dass es keine Nachteile gegenüber memcpy hat, aber man damit ein paar Sachen machen kann, die mit memcpy nicht gehen.

    hackglobal schrieb:

    was ich so sehe ist memcpy schneller als std::copy! stimmt das? warum soll man dann std::copy nehmen?

    Wie siehst du das? Das sollte intern zu memcpy optimiert werden. Vergleichst du etwa unoptimierten Code?



  • hackglobal schrieb:

    tntnet...das war ja nur um den string auszugeben fuers debuging....

    das eigentlich flush soll ueber das netzwerk passieren...

    was mache ich wenn der buffer voll ist und und die write funktion noch einmal geschrieben wird?

    was will der interviewer eigentlich rausfinden, wenn er dich einen bufferedwriter implementieren laesst?

    Was interessiert mich ein Interviewer. Du hast eine Frage zum bufferedWriter gestellt und ich habe das kommentiert.

    Wäre ich Interviewer und würde so eine Frage stellen, dann würde ich prüfen wollen, ob einer blind einen bufferedWriter auf std::iostream (bzw. std::ostream) schreibt oder eher nachfragt. Ich will Leute haben, die mit denken.



  • hackglobal schrieb:

    Die Daten auf/in die "Sink" schreiben?

    ja, die sink ist eine TCP verbindung... dh der buffer muesste fuer die zeit blockiert werden...

    kann ich eine art double buffer bauen, falls waehrend dem senden ueber tcp dei write funktion noch einmal aufgerufen wird?

    Die Frage stellt sich schon mal nur wenn du asynchron sendest.
    Sendest du asynchron?

    Ansonsten: ja, klar kannst du double-buffering verwenden. Oder triple-buffering. Oder N-fach-buffering.
    Fragt sich nur ob es notwendig bzw. überhaupt sinnvoll ist.



  • nein, sende synchron...



  • Und wie soll dann write() aufgerufen werden während noch gesendet wird?
    Aus nem anderen Fred etwa?
    Dann fehlt da aber noch einiges...


Anmelden zum Antworten