C Programm arbeitet genauso langsam wie im Java (brauche Hilfe)...
-
Shoenen Zeitpunkt,
vor kurzem have ich ne Kurze Methode entwickelt, die aus einem String-text
alle IPv4- aenliche Substrings (d.h. "nnn.nnn.nnn.nnn") sucht und in irgendeiner Form rausgibt. Geschwindichkeit have ich getestet in: C Java und php
Php arbeitet ca. 100 mal langsamer als die beide, aber
das bloede dabei ist dass die C und Java Kode fast dasselbe Zeit brauchen
(21 sek Java vergl. 19 sek C) und ich habe keine Ahnung wie man dies in C noch optimisieren soll:struct strStack{ char * string; struct strStack * next; }; char ** findip4(char* text){ char ** ret; unsigned int retSize = 0; struct strStack *stackRoot = (struct strStack *) malloc (sizeof (struct strStack)); // The pointer to the begin of stack must be constant struct strStack *stackPtr = stackRoot; char * curStr = (char *) malloc (16); curStr[15] = '\0'; unsigned char chr = text[0], lim = 0, mode = 0, chrPos = 0; unsigned int i = 0; while (chr){ //yeah, C is awsome :D switch (mode){ case 0: if((47<chr)&&(chr<58)){ curStr[chrPos++] = chr; lim++; mode++; }break; //of case 0 case 1: case 3: case 5: if(((47<chr) && (chr<58) && (lim<3))){ curStr[chrPos++] = chr; lim++; }else if (46 ==chr){ curStr[chrPos++] = '.'; lim = 0; mode++; }else { chrPos = 0; lim = 0; mode = 0; } break; case 2: case 4: case 6: if((47<chr) && (chr<58)){ curStr[chrPos++] = chr; lim++; mode++; }else{ chrPos = 0; lim = 0; mode = 0; } break; case 7: if((47<chr) && (chr<58)){ if (lim<3){ curStr[chrPos++] = chr; lim++; }else{ stackPtr->string = curStr; //Adding a string to stack stackPtr->next = (struct strStack *) malloc (sizeof (struct strStack)); //we allocated the next stack element stackPtr = stackPtr->next; //go to the next //element of the stack curStr = (char *) malloc (16); // We //allocate new current String curStr[15] = '\0'; retSize++; chrPos = 0; lim = 0; mode = 0; };//end of if ($lim<4) }else{ //yes the same code must be here its ok :D stackPtr->string = curStr; //Adding a string to stack stackPtr->next = (struct strStack *) malloc (sizeof (struct strStack)); //we allocated the next stack element stackPtr = stackPtr->next; //go to the next //element of the stack curStr = (char *) malloc (16); // We //allocate new current String curStr[15] = '\0'; retSize++; chrPos = 0; lim = 0; mode = 0; } ;//end of case 7: if... break; };//end of switch i++; chr = text[i]; };//end of while if(chrPos && mode == 7){ //we must add the last element to stack: stackPtr->string = curStr; //Adding a string to //stack retSize++; } // we dont change another variables since we dont need them //optional :at the end we must convert the stack into the array of //strings: ret = (char *)malloc ((retSize +1) * sizeof (char *)); ret[retSize] =0; struct strStack *stackPtr2 = stackRoot; i = 0; while(retSize){ ret[i++] = stackPtr2->string; //Set the current stack pointer to string into array elemenr stackPtr2 = stackPtr2->next; //and go to the next element of the stack retSize--; } return ret; }; // end of findipv4
Ich mache eine Stack - Struktur weil Anzahl von ip4 - substrings unbekannt ist.
Zum vergleich noch Java Kode dieser Methode:
import java.util.ArrayList; import java.util.List; public class SubstringFinder { public static void main(String[] args) { //test: String text ="abd\n\n\tc\r123.198.77.001fddfsd245.223.54.345 546.345.234..543gd"+ "asdadfsdfgdfgdfgdg1233.4444.5555.666.777.888.999.dfgadfgkajhdfogiuadf" + "oiguahdfgjandlfgadfgaldfjkgaldkfjghaldkfjghalkdjfghakljdfhgklajdfhgkljd" + "fhlgkjadf444.444.44.44.1.1.1.1.1.1.1.1.1.1.1.1.2.2.2.2.dfgdfgdfgdfdfgdfgdf" + "sdfgjksfhgisudfhgjnwe.e,rrmnw.e,rndk;fjgnd;kfjgnw.,rmn;kjdfs;kdjgndfg" + "#$%#$%.@$@#$2.qweqwr.2#$@#4.wer.er.e.e.r4f.5g.3d.34.df.45.45.45.45g"+ "abd\n ; // *** TIME TEST: long timeInMillis = System.currentTimeMillis(); for(int i=0;i < 10000000; i++)findip4(text); long timeInMillis2 = System.currentTimeMillis(); System.out.println( (timeInMillis2-timeInMillis) +" : Milisekonds ");//100000 = near 1 sek for(String ip4s:findip4(text)) System.out.println(ip4s); //simple test } public static List<String> findip4(String text){ List<String> ret = new ArrayList<String>(); char[] charArray = text.toCharArray(); int charLen = text.length(); char chr = 0; StringBuilder curStr = new StringBuilder(); byte lim = 0; byte mode =0; for(int i =0; i < charLen; i++){ chr = charArray[i]; switch(mode){ case 0 : if ((47<chr)&&(chr<58)){ curStr.append(chr); lim++; mode++; } break; case 1: case 3: case 5: if(((47<chr) && (chr<58) && (lim<3))){ curStr.append(chr); lim++; }else if (46 ==chr){ curStr.append('.'); lim = 0; mode++; }else { curStr.setLength(0); lim = 0; mode = 0; } break; case 2: case 4: case 6: if((47<chr) && (chr<58)){ // if digit we add a dot and go to the next mode curStr.append(chr); lim++; mode++; }else{ // if not digit after a dot: curStr.setLength(0); lim = 0; mode = 0; }; break; case 7: if((47<chr) && (chr<58)){//if digit - the last digits sequence if (lim<3){ curStr.append(chr); lim++; }else{ ret.add(curStr.toString()); //adding current ip4-string to the array curStr.setLength(0); lim = 0; mode = 0; };//end of if ($lim<4) }else{ ret.add(curStr.toString()); //adding current ip4-string to the array curStr.setLength(0); lim = 0; mode = 0; } ;//end of case 7: if... break; };//end of switch }; //end of for if(curStr.length()!= 0 && mode == 7) ret.add(curStr.toString());// adding the last ip4-string return ret; };//end of findip4 }
Und PHP, vllt weiss jemand wie man den beschleunigen koennte :
<?php #finds in the (hyper)text all ***.***.***.*** Substrings , #written in C - style ;D #no "tidy html" or any other parcing tool needed #for beter performance (is that so?) i work on low lvl of string processing # #quote from http://www.wellho.net/solutions/php-an-overview-of-php-string-functions.html: # #LOW LEVEL FUNCTIONS (are): #Functions that you can use to find out how long a string is, #where one string occurs for the first time in another, #to replace part of one string (given a starting point and length) #with another, etc. Also functions to compare strings to see which comes first / last in sorting. #Low level functions are (roughly) equivalent to the functions you have #in a language such as C. You can do more or less anything with them, #but you have a lot of code to write to do so. In PHP, the low level #functions are important only where you have a specialist requirement #that can't be met by the other types of functions. #ASCII enkoding for strings are : 48 for '0' , 57 for '9' , 46 for '.' # USAGE EXAMPLE: $testStr = "abd\n\n\tc\r123.198.77.001fddfsd245.223.54.345 546.345.234..543gd". "asdadfsdfgdfgdfgdg1233.4444.5555.666.777.888.999.dfgadfgkajhdfogiuadf" . "oiguahdfgjandlfgadfgaldfjkgaldkfjghaldkfjghalkdjfghakljdfhgklajdfhgkljd" . "fhlgkjadf444.444.44.44.1.1.1.1.1.1.1.1.1.1.1.1.2.2.2.2.dfgdfgdfgdfdfgdfgdf" . "sdfgjksfhgisudfhgjnwe.e,rrmnw.e,rndk;fjgnd;kfjgnw.,rmn;kjdfs;kdjgndfg" . "#$%#$%.@$@#$2.qweqwr.2#$@#4.wer.er.e.e.r4f.5g.3d.34.df.45.45.45.45g"; echo "speedtest\n"; for($i =0; $i < 10000; $i +=1) findIp4s($testStr); echoArrayAsLines(findIp4s($testStr)); function echoArrayAsList($arr){ echo"<ul>"; foreach($arr as $item) echo "<li>$item</li>" ; echo"</ul>"; } function echoArrayAsLines($arr){ echo"-----\n"; foreach($arr as $item) echo "* $item \n" ; echo"-----\n"; } function findIp4s($str){ $charArray = preg_split('//',$str); # split it in array of chars $charLen = strlen($str); # length of string $char = "\0"; # charakter variable $charInt = 0 ; # charakter ASCII nummer $ret = array(); # return array $curStr = ""; # the ip4 substrings we are parcing $lim = 0; # limit of ip4 a $mode = 0; # 0 - not an ip4 substring , 1 - A, 2 - dot, # 3 - B , 4 - dot, 5 - C ,6 - dot, 7 - D for($i = 0; $i < $charLen;$i++){ #echo "char $i: mode $mode : str $curStr\n";#for debugging $char = $str{$i}; # gets the character $charInt = ord($char); # gets the ASCII- Numer of the character switch ($mode){ case 0: if((47<$charInt) and ($charInt<58)){ # if '0' < $char < '9' , lasy evaluated , use & for strikt $curStr .= $char; # used separately from cases 2,4 and 6 # for not spamming the else - operator $lim += 1; $mode += 1; }; break; case 1: case 3: case 5: if(((47<$charInt) and ($charInt<58) and ($lim<3))){ $curStr .= $char; $lim += 1; } elseif (46 == $charInt){# if dot we add it and go to the next mode $curStr .='.'; $lim = 0; $mode += 1; } else{#too many symbols or not digit $curStr = ""; $lim = 0; $mode = 0; }; break; case 2: case 4: case 6: if((47<$charInt) and ($charInt<58)){ # if digit we add a dot and go to the next mode $curStr .= $char; $lim += 1; $mode += 1; }else{ # if not digit after a dot: $curStr = ""; $lim = 0; $mode = 0; }; break; case 7: if((47<$charInt) and ($charInt<58)){#if digit - the last digits sequence if ($lim<3){ $curStr .= $char; $lim += 1; }else{ $ret[] = $curStr; #adding current ip4-string to the array #echo $curStr . "\n"; #info for debugging $curStr = ""; $lim = 0; $mode = 0; };#end of if ($lim<4) }else{ $ret[] = $curStr; $curStr = ""; $lim = 0; $mode = 0; } ;#end of case 7: if... break; };#end of switch };#end of for if((strlen($curStr)!= 0) and ($mode == 7)) $ret[] = $curStr;# adding the last ip4-string return $ret; };#end of funktion findIp4 ?>
W[rde sehr dankbar sein fuer Hilfe
-
Anstatt 3x100 Zeilen Code zu analysieren, schieße ich einfach mal ins Blaue: Dumme Compileroptionen? Zwischen unoptimiertem Code und optimiertem Code liegt locker mal ein Faktor 5-10. Faktor 100 bei einem unoptimiertem Debugbuild.
Die Javaruntime, die ja so eine Art optimierten Debugcode ausführt, solltest du jedenfalls bei Stringverarbeitung ganz locker abhängen können.
Ist das eigentlich Code, der ernsthaft schnell sein soll oder nur ein Sprachbenchmark? Weil das Problem geht bestimmt auch besser zu lösen, insbesondere passen verkettete Listen und Performance nicht so recht zusammen.
-
Der Code ist viel zu umständlich und macht um Größenordnungen zu viele Speicheranforderungen. Ich sehe kein einziges
free
. Du beherrschst die Syntax von C nicht einmal vernünftig, überall magische Zahlen. Lern doch erstmal Programmieren, bevor du irgendwelche Benchmarks schreibst.
-
Nein dies ist kein Benchmark, ich will einfach dies moeglichst schnell laufen zu kriegen und ueberrascht war das die Ergebnisse so sind.
Die Listen gefallen mir auch nicht so wirklich, aber wie soll man ohne dies es zu loesen.
Uebrigens habe ich die Geschwindigkeit von einer "dummy"- Methode
getestet dies verbraucht 12 Sekunden (grob so zu sagen) von der 19 Sekunden
von kompletten Methode:void dummy(char * text){ char chr = text[0],dummy = 0; int i =0; while(chr) { dummy = ((47<chr) && (chr<58)); i++; chr =text[i]; }; };
Dumme Compileroptionen?
Ja jetzt kommen wir vllt. zum wahres Grund , was fuer Optionen besser sind in dem Fall?
Ich sehe kein einziges free
Dies wuerde den noch verlangsamen, aus bestimmten gruenden ist mir Arbeistpeicher erst ...egal :D.
-
o4kareg schrieb:
Nein dies ist kein Benchmark, ich will einfach dies moeglichst schnell laufen zu kriegen und ueberrascht war das die Ergebnisse so sind.
Dann: STOPP!
Wie TyRoXx und ich schon angedeutet haben, der Code ist derzeit eher ... suboptimal.
Erklär mal ganz genau, was dein Code machen soll, am besten mit Beispielen. Dann kann man gemeinsam was gutes ausarbeiten. Und muss es C sein oder darf es auch C++ sein?
Dumme Compileroptionen?
Ja jetzt kommen wir vllt. zum wahres Grund , was fuer Optionen besser sind in dem Fall?
Na, irgendwelche. Du musst deine Werkzeuge schon selber beherrschen. Anleitung findest du bei Google und beim Compiler dabei (und der erste Treffer bei Google wird wahrscheinlich nochmals genau jene Anleitung sein)
Dies wuerde den noch verlangsamen, aus bestimmten gruenden ist mir Arbeistpeicher erst ...egal
Nein, es ist nicht egal. Wer schlampig programmiert der denkt auch erfahrungsgemäß schlampig. Schlampige Algorithmen schlampig programmiert sind langsam, fehleranfällig und schwer zu warten. [*]
[*]: Jetzt wo ich das geschrieben habe, komme ich nicht drumrum anzumerken, dass dies deinen oben gezeigten Code recht gut beschreibt.
-
Mal was anderes:
Wenn du mitdummy = ((47<chr) && (chr<58));
dummy = (('0'<=chr) && (chr<='9'));
meinst, dann kannst du das auch schreiben.
Oder besserdummy = isdigit(chr);
Und in Zeile 69:
};//end of if ($lim<4)
Nur gibt es dieses if nirgends.
Wenn du möchtest, das dir jemand hilft, räum deinen Code auf. Auch optisch.
-
o4kareg schrieb:
Die Listen gefallen mir auch nicht so wirklich, aber wie soll man ohne dies es zu loesen.
Mit einem Array, das alle 2^n Elemente mit
realloc
vergrößert wird.#include <stdlib.h> #include <string.h> #include <stdio.h> typedef struct address { //wird nie länger als 16 char str[16]; } address; typedef struct address_vector { address *elements; size_t used; size_t allocated; } address_vector; void init_address_vector(address_vector *v) { v->elements = 0; v->used = 0; v->allocated = 0; } void free_address_vector(address_vector *v) { free(v->elements); } void add_address(address_vector *v, const address *element) { if (v->allocated == v->used) { if (v->allocated == 0) { v->allocated = 4; } else { v->allocated *= 2; } v->elements = realloc(v->elements, sizeof(*v->elements) * v->allocated); } v->elements[v->used] = *element; ++(v->used); } int main() { size_t i; address_vector v; address a = {{"8.8.8.8"}}; init_address_vector(&v); add_address(&v, &a); for (i = 0; i < v.used; ++i) { printf("%s\n", v.elements[i].str); } free_address_vector(&v); return 0; }
o4kareg schrieb:
Dumme Compileroptionen?
Ja jetzt kommen wir vllt. zum wahres Grund , was fuer Optionen besser sind in dem Fall?
Aber klar, immer sind die anderen Schuld..
-
Java Code aufräumen ganz einfach:
// Performance Trick for Speed Up private static Pattern pattern = Pattern.compile("[0-9]{1,3}+\\.[0-9]{1,3}+\\.[0-9]{1,3}+\\.[0-9]{1,3}+"); public static List<String> findip4(String text){ List<String> ret = new ArrayList<>(); Matcher matcher = pattern.matcher(text); while(matcher.find()) { ret.add(matcher.group()); } return ret; }
Ergebnis ist korrekter anscheinend, aber (bei mir) auch langsamer.
123.198.77.001 245.223.54.345 555.666.777.888 444.444.44.44 1.1.1.1 1.1.1.1 1.1.1.1 2.2.2.2 45.45.45.45
anstelle von
123.198.77.001 245.223.54.345 666.777.888.999 444.444.44.44 1.1.1.1 1.1.1.1 1.1.1.1 2.2.2.2 45.45.45.45
-
TyRoXx schrieb:
v->elements = realloc(v->elements, sizeof(*v->elements) * v->allocated);
Recht übel, realloc kann auch NULL liefern -> Speicherleck und alle Daten pfutsch. Excception-verwöhnt?
-
Thorgrim schrieb:
TyRoXx schrieb:
v->elements = realloc(v->elements, sizeof(*v->elements) * v->allocated);
Recht übel, realloc kann auch NULL liefern -> Speicherleck und alle Daten pfutsch. Excception-verwöhnt?
Ja, das habe ich ganz vergessen.
So besser?
#include <stdlib.h> #include <string.h> #include <stdio.h> typedef struct address { //wird nie länger als 16 char str[16]; } address; typedef struct address_vector { address *elements; size_t used; size_t allocated; } address_vector; void init_address_vector(address_vector *v) { v->elements = 0; v->used = 0; v->allocated = 0; } void free_address_vector(address_vector *v) { free(v->elements); } int add_address(address_vector *v, const address *element) { if (v->allocated == v->used) { address *new_elements; size_t reallocated; if (v->allocated == 0) { reallocated = 4; } else { reallocated = (v->allocated * 2); } new_elements = realloc(v->elements, sizeof(*v->elements) * reallocated); if (!new_elements) { return 0; } v->elements = new_elements; v->allocated = reallocated; } v->elements[v->used] = *element; ++(v->used); return 1; } int main() { size_t i; address_vector v; address a = {{"8.8.8.8"}}; init_address_vector(&v); for (i = 0; i < 10; ++i) { if (!add_address(&v, &a)) { fprintf(stderr, "Allocation failed\n"); free_address_vector(&v); return 1; } } for (i = 0; i < v.used; ++i) { printf("%s\n", v.elements[i].str); } free_address_vector(&v); return 0; }
-
Danke Leute, also hauptsache liegt es nur in Allocationen. Oder in dem Vergleich?
Ist isdigit() schneller?Der Ratschlag
Mit einem Array, das alle 2^n Elemente mit realloc vergrößert wird.
klingt gut, bzw. koennte man sogar. mit zwei (grossen) statischen Array auskommen, und als einer voll wird mit anderem Thread die IPs in Text-File zu speichern.
Danke auch fuer Java- code (ich kannte nicht die Methode) aber selbstverstaendlich wurde dieser Aufruf langsamer sein.
-
Wenn es nur darum geht, die IPs aus dem Text rauszugreppen und in eine Datei zu speichern, kannst du dir die Kopiererei von vorneherein sparen und das alles in einem Rutsch machen. Dann entfällt auch die Speicherverwaltung vollständig.
Was den Algorithmus und seine Optimierung angeht, hängen die Details von den erwarteten Eingabedaten ab. Erwartest du eine Menge Text, in dem ein paar IP-Adressen stehen, oder eine Liste von IP-Adressen mit ein paar Zeichen hier und da dazwischen?
Außerdem: Aus "1.2.3.4.5" lässt sich sowohl "1.2.3.4" als auch "2.3.4.5" herauslesen, und aus "12.34.56.78" auch "2.34.56.78", "12.34.56.7" und "2.34.56.7". Außerdem ist es mit Zahlen allein nicht getan, denn "1.2.3.456" ist keine gültige IP-Adresse (obwohl man da "1.2.3.45" herausparsen könnte). Wie soll mit dieser Problematik umgegangen werden?
-
Nachtrag: Ich denke mir das etwa so:
#include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> static char const *const text = "abd\n\n\tc\r123.198.77.001fddfsd245.223.54.345 546.345.234..543gd" "asdadfsdfgdfgdfgdg1233.4444.5555.666.777.888.999.dfgadfgkajhdfogiuadf" "oiguahdfgjandlfgadfgaldfjkgaldkfjghaldkfjghalkdjfghakljdfhgklajdfhgkljd" "fhlgkjadf444.444.44.44.1.1.1.1.1.1.1.1.1.1.1.1.2.2.2.2.dfgdfgdfgdfdfgdfgdf" "sdfgjksfhgisudfhgjnwe.e,rrmnw.e,rndk;fjgnd;kfjgnw.,rmn;kjdfs;kdjgndfg" "#$%#$%.@$@#$2.qweqwr.2#$@#4.wer.er.e.e.r4f.5g.3d.34.df.45.45.45.45g" "abd\n"; int main(void) { char const *p = text; char const *p_vorn = p; while((p_vorn = p = strpbrk(p, "123456789"))) { int octet_count; for(octet_count = 0; octet_count < 4; ++octet_count, ++p) { int digits; for(digits = 0; digits < 3 && isdigit(*p); ++digits, ++p) { } if(digits == 0 || (*p != '.' && octet_count != 3)) break; } if(octet_count == 4) { /* Hier dann halt statt stdout deine Datei */ fwrite(p_vorn, sizeof(char), p - p_vorn - 1, stdout); putchar('\n'); } } return 0; }
Ob die Verwendung von strpbrk in dieser Form sich lohnt, sollte anhand typischer Eingabedaten ausgemessen werden; es dürfte vor allem dann der Fall sein, wenn längere Textstellen ohne Ziffern vorkommen, also viel auf einmal übersprungen wird. Andernfalls kann der strpbrk-Aufruf durch die Funktion
char const *skip_nondigits_and_zeroes(char const *str) { for(; *str && (*str < '1' || *str > '9'); ++str) ; return *str ? str : NULL; }
oder so ersetzt werden.
Merke: 1233.4444.5555.666.777.888.999 wird von diesem Algorithmus nur mäßig sinnvoll behandelt.
-
alle IPv4- aenliche Substrings (d.h. "nnn.nnn.nnn.nnn")
Definiere das mal richtig, so dass eine check-Funktion geschrieben werden kann, die true/false zurueckgibt, wenn der uebergebene String deine Kriterien entspricht/nicht entspricht.
-
o4kareg schrieb:
das bloede dabei ist dass die C und Java Kode fast dasselbe Zeit brauchen
Das halte ich bei diesen Aufgabenstellungen für unhaltbar.
o4kareg schrieb:
(21 sek Java vergl. 19 sek C) und ich habe keine Ahnung wie man dies in C noch optimisieren soll:
Jedenfalls nicht mit verketteten Listen, verkettete Listen und Performanz schließen sich gegenseitig aus.
char **ipv4(const char *s) { int n,n0,n1,n2,n3; char *r=calloc(2,strlen(s)),**p=r,*c=r+strlen(s)/2; while( EOF!=sscanf(s,"%*[^0-9]%n",&n) ) if( n0=n1=n2=n3=0,sscanf(s+=n,"%*3[0-9]%n.%*3[0-9]%n.%*3[0-9]%n.%*3[0-9]%n",&n0,&n1,&n2,&n3), n3 ) { memcpy(c,s,n3); *p++=c+=n3+1; s+=n3; } else s+=n2?n2:n1?n1:n0; return r; } int main() { char **p=ipv4("abd\n\n\tc\r123.198.77.001fddfsd245.223.54.345 546.345.234..543gd" "asdadfsdfgdfgdfgdg1233.4444.5555.666.777.888.999.dfgadfgkajhdfogiuadf" "oiguahdfgjandlfgadfgaldfjkgaldkfjghaldkfjghalkdjfghakljdfhgklajdfhgkljd" "fhlgkjadf444.444.44.44.1.1.1.1.1.1.1.1.1.1.1.1.2.2.2.2.dfgdfgdfgdfdfgdfgdf" "sdfgjksfhgisudfhgjnwe.e,rrmnw.e,rndk;fjgnd;kfjgnw.,rmn;kjdfs;kdjgndfg" "#$%#$%.@$@#$2.qweqwr.2#$@#4.wer.er.e.e.r4f.5g.3d.34.df.45.45.45.45g" "abd\n"),*r=p; while( *p ) puts(*p++); free(r); return 0; }