Vergleich C++ vs. Python

Aus revampedia
Version vom 13. Mai 2015, 16:27 Uhr von Cem Aydin (Diskussion | Beiträge) (init)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)

Motivation

Als ich den apybot programmiert habe hatte ich Lust die Performance von Python mit einer anderen Programmiersprache vergleichen.

Auch da ich finde, dass sich die Parserfunktion für IRC Nachrichten dafür gut eignet. Diese ist ziemlich einfach zu programmieren und lässt sich in einer Schleife wiederholen. Ob das wirklich einen guten Benchmark ergibt, kann ich nicht wirklich beurteilen. (Ist mir aber auch egal.)

Code

Der Code soll eine Datei mit IRC Nachrichten lesen. Diese in prefix, command, arguments und text, teilen und zurückliefern.

Python Code:

#!/usr/bin/python3
#
# test parser speed
#
# myparser
#

def split_recv_msg(line):
    '''Split received IRC message into defined parts.

Returns: prefix command args text'''

    # opt: use else instead of default value to avoid write
    #prefix = None
    #text = None

    if line[0] == ':':
        prefix, line = line[1:].split(' ', 1)
    else:
        prefix = None

    if line.find(' :') != -1:
        line, text = line.split(' :', 1)
    else:
        text = None

    if line.find(' ') != -1:
        command, line = line.split(' ', 1)
        args = line.split()
    else:
        command = line
        args = None

    return prefix, command, args, text

TESTFILE = "output.file.big"

for line in open(TESTFILE, 'r'):

    sline = split_recv_msg(line)
    #sline = split_recv_msg(line)

    #print("sline: ", sline)

C++ Code:

<source lang=cpp> // parsing IRC message in c++

  1. include <iostream>
  2. include <string>
  3. include <vector>
  4. include <iterator>
  5. include <fstream>
  6. include <sstream>

//using namespace std;


struct msg_struct {

   std::string prefix;
   std::string command;
   std::vector<std::string> args;
   std::string text;

};

void split_msg_line(std::string& line, msg_struct& line_parts) {

   // (string and vector are empty by default!
   // still have to set it in the else or it will stay
   // at the value of the last run...)
   // get prefix
   if (line[0] == ':') {
       std::size_t pref_break_pos = line.find(' ');
       // set prefix
       line_parts.prefix = line.substr(1, pref_break_pos-1);
       line = line.substr(pref_break_pos+1);
       //std::cout << line << std::endl;
   }
   else {
       line_parts.prefix.clear();
   }
   // get text
   std::size_t text_break_pos = line.find(" :");
   if (text_break_pos != std::string::npos) {
       // set text
       line_parts.text = line.substr(text_break_pos+2);
       line = line.substr(0, text_break_pos);
       //std::cout << '"' << line << '"' << std::endl;
   }
   else {
       line_parts.text.clear();
   }
   // get command
   // (clear args vector!)
   line_parts.args.clear();
   std::size_t command_end_pos = line.find(' ');
   if (command_end_pos != std::string::npos) {
       line_parts.command = line.substr(0, command_end_pos);
       line = line.substr(command_end_pos+1);
       //std::cout << '"' << line << '"' << std::endl;
       // parse args
       // http://stackoverflow.com/questions/236129/split-a-string-in-c
       int start = 0, end = 0;
       while ((end = line.find(' ', start)) != std::string::npos) {
           line_parts.args.push_back(line.substr(start, end - start));
           start = end + 1;
       }
       line_parts.args.push_back(line.substr(start));
   }
   // else command=line
   else {
       line_parts.command = line;
   }


}

int main() {

   // initialize output structure
   msg_struct line_parts_out;
   // line examples
   //std::string regi_str = ":orwell.freenode.net 001 pybot_ :Welcome to the freenode Internet Relay Chat Network pybot_";
   //std::string regi_str = "001 :hoho";
   //std::string regi_str = "001 gaga abc :Welcome to the freenode Internet Relay Chat Network pybot_";
   // read file line by line
   // http://stackoverflow.com/questions/7868936/read-file-line-by-line
   std::ifstream infile("output.file.big");
   // process line by line
   std::string line;
   while (std::getline(infile, line)) {
       split_msg_line(line, line_parts_out);
       // concise output

/* std::cout << "p: " << '"' << line_parts_out.prefix << '"';

       std::cout << " c: " << '"' << line_parts_out.command << '"';
       std::cout << " a: [ ";
       std::vector<std::string>::iterator it;
       for (it=line_parts_out.args.begin(); it<line_parts_out.args.end(); it++)
           std::cout << '"' << *it << '"' << ' ' ;
       std::cout << "]";
       std::cout << " t: " << '"' << line_parts_out.text << '"' << std::endl;
  • /
       // verbose output

/* std::cout << "prefix: " << '"' << line_parts_out.prefix << '"' << std::endl;

       std::cout << "text: " << '"' << line_parts_out.text << '"' << std::endl;
       std::cout << "command: " << '"' << line_parts_out.command << '"' << std::endl;
       std::cout << "args: [ ";
       std::vector<std::string>::iterator it;
       for (it=line_parts_out.args.begin(); it<line_parts_out.args.end(); it++)
           std::cout << '"' << *it << '"' << ' ' ;
       std::cout << "]" << std::endl;
  • /
   }

} \\

Durchführung

Getested habe ich mit einer Datei die 34220 IRC Zeilen enthält (erzeugt in bash durch wiederholung von ca. 10 Zeilen, mit `cat` und `for`).

Die Zeit habe ich mittels `time` befehl gestoppt. Beispiel: $ time ./parse-my.py

real 0m0.210s user 0m0.196s sys 0m0.016s

Resultate

Der C++ Code ist auch um einiges länger, komplizierter und war für mich wesentlich schwieriger zu schreiben. Die Entwicklung hat auch entsprechen ca. 10x solange gedauert.

Python braucht ca 0.2 Sekunden. C++ erledigt das in ca. 0.1 Sekunden.