Adott egy szkiptem, amit nagyobb mennyiségű adat feldolgozására szeretnék használni. A szkript fut is rendesen, és helyesen dolgozik, viszont nagyon lassan.
Összesen egy óra alatt egy példány csak ~1 MB adattal végzett, és egy-egy példányra kb 1 GB-nyi bemeneti adat jutna.
A vicc az, hogy az egyes példányok CPU használata 1% körül van.
Ennyire sokat számítana az alkalmazások indítása, és az i/o műveletek?
Itt a kód:
#!/bin/bash
INPUT="$1"
OUTPUT="$2"
BAD="$3"
echo -n > "$OUTPUT"
echo -n > "$BAD"
while read A; do
N=`echo "$A" | rev | cut -c 1`
case "$N" in
( '1' | '3' | '7' | '9' )
echo "$A" >> "$OUTPUT"
;;
*)
echo "$A" >> "$BAD"
;;
esac
done < "$INPUT"
- 1533 megtekintés
Hozzászólások
pastebin ^ ^
- A hozzászóláshoz be kell jelentkezni
kispill
szerk: ezért a 10 sorért felesleges a pastebin.
__________________________________________________________
Az életben csak egy dolog a szép, de az épp nem jut eszembe.
Slackware Linux 12.1 | 2.6.26.7-janos
- A hozzászóláshoz be kell jelentkezni
egrep "[1379]$" inputfile >outfile
egrep -v "[1379]$" inputfile >badfile
- A hozzászóláshoz be kell jelentkezni
először ezt próbáltam én is.
viszont az történt, hogy a kimeneti fájlokban megjelent az adatok nagy része, utána már a grep nem küldött beléjük semmit, ellenben 100%-on járatta a procit órákig, és nem volt kedvem és időm kivárni a végét.
ennek az elkerülése végett írtam a bash szkriptet.
__________________________________________________________
Az életben csak egy dolog a szép, de az épp nem jut eszembe.
Slackware Linux 12.1 | 2.6.26.7-janos
- A hozzászóláshoz be kell jelentkezni
Itt vmi nagyon nem stimmel -- nem a scripttel --, min/hogyan futtatod a scriptet?
- A hozzászóláshoz be kell jelentkezni
xterm-ből, egy 3 GHz-es HT-s p4-en, 2 GB rammal.
__________________________________________________________
Az életben csak egy dolog a szép, de az épp nem jut eszembe.
Slackware Linux 12.1 | 2.6.26.7-janos
- A hozzászóláshoz be kell jelentkezni
Szabalyos (regular) file az input?
/dev/null-ba cat-olva az inputot mennyi ido alatt fut le?
- A hozzászóláshoz be kell jelentkezni
igen, reguláris fájl.
catoltam már más parancs stin-jére, és ott sem volt gond.
__________________________________________________________
Az életben csak egy dolog a szép, de az épp nem jut eszembe.
Slackware Linux 12.1 | 2.6.26.7-janos
- A hozzászóláshoz be kell jelentkezni
Nemtom, de az a 100%-on futo, es semmit nem termelo egrep nagyon csunyan hangzik...
- A hozzászóláshoz be kell jelentkezni
Eredetivel szemben ez kétszer olvassa inputfile -t. (Ami itt nem látszik problémának, de máshol még lehet az.) Úgyhogy legyen itt egy megoldás pl. sed -del, egyszeri végigolvasással:
sed -n -e '/[1357]$/w outfile' -e '/[^1357]$/w badfile' inputfile
Jav: meg egy awk-ban is:
awk '{ if ( $0 ~ /[1357]$/) {print > "outfile"; } else { print > "badfile" ; } }' inputfile
- A hozzászóláshoz be kell jelentkezni
N=`echo "$A" | rev | cut -c 1`
No itt elindítasz kismillió processzt. E helyett próbáld ezt:
N=${A#${A%?}}
Legalábbis ha jól értem, hogy te az A-ban található szöveg utolsó karakterét akarod. (Fenti ocsmányság a shell saját mechanizmusát használja: A-ból eldobja előlről azt a sztringet, amit úgy kap, hogy eldobja az utolsó karaktert :-) Lehet, hogy bash-ba van rá valami egyszerűbb rondaság, ez viszont megy más shell-ekben is.)
- A hozzászóláshoz be kell jelentkezni
kipróbálom ezt is, csak hát elég randa volt, és nem értettem, hogy pontosan hogyan csinálja, és ezért nem használtam ezt a módot.
még délelőtt rágoogliztam és ezeket a módokat találtam itt:
sed 's/.*\(.\)$/\1/' input
GNU and some implementations of New AWK
awk '{print $NF}' FS= input
perl -nle'print/(.)$/' input
or
perl -lne'print chop' input
ruby -ne'puts$_[/.$/].to_s' input
while IFS= read -r; do printf "%s\n" "${REPLY#${REPLY%?}}";done <input
With recent versions of bash:
while IFS= read -r; do printf "%s\n" "${REPLY[ -1]}";done<input
With zsh:
while IFS= read -r;do print -- $REPLY[-1];done<input
If rev and process substitution are available:
cut< <(rev input) -c1
Or with GNU grep (this won't display empty lines):
grep -Eo '.$' input
__________________________________________________________
Az életben csak egy dolog a szép, de az épp nem jut eszembe.
Slackware Linux 12.1 | 2.6.26.7-janos
- A hozzászóláshoz be kell jelentkezni
No az a REPLY -os while ugyanazt csinálja, mint amit én írtam. Az összes while -os futtat egy ciklust ki tudja miért, a maradéknak meg ugyanaz a baja, mint a tiednek: feleslegesen csinál baromi sok processzt.
Szóval igazán gyors eredményt valószínűleg valami jól megfogott sed/awk/grep párossal érnél el, a shell megvalósítást szinte biztos nagyon fel tudnád gyorsítani, de nem eléggé. Ja és még valami: még annyit tennék hozzá, hogy az egyik kimeneti fájlt csak egyszer irányítanám át - a ciklus záró parancsánál (logikusan azt, aminél több kimenet várható - már ha egyáltalán ilyet tudsz) - valahogy így:
while read A; do
N=${A#${A%?}}
case "$N" in
( '1' | '3' | '7' | '9' )
echo "$A"
;;
*)
echo "$A" >> "$BAD"
;;
esac
done < "$INPUT" > "$OUTPUT"
(esetleg a másik echo-t echo >&2 -re átírni, és a done után egy 2> "$BAD" - ezzel összesen két darab fájlmegnyitás lesz - merthogy a baromi sok processz létrehozáson kívül a baromi sok fájlnyitás/zárás is lassít rendesen.)
- A hozzászóláshoz be kell jelentkezni
igen, teljesen jogos.
ellenben nem látom tünetét annak, hogy a kis usb-s rack nagyon szétseekelné magát. Igazából nem is nagyon mutat aktivitást.
__________________________________________________________
Az életben csak egy dolog a szép, de az épp nem jut eszembe.
Slackware Linux 12.1 | 2.6.26.7-janos
- A hozzászóláshoz be kell jelentkezni
Nem kell feltétlenül seek-elgetni. Magának az open/close hívásnak is van jócskán overhead-je, te meg mindegy egyes sornál csinálsz egy nyitás/zárást. Ez igazából ugyanúgy kernel szintű adminisztráció, mint ahogy normális esetben az echo | rev | cut esetén se nagyon fogja minden sornál betölteni a kernel a binárisokat, de a csövek megcsinálása, a processzek létrehozás, indítása, stdin/stdout "átirányítás" elvégzése is tisztán kernel admnisztrációt okoz - ez pedig egyértelműen CPU-terhelés -> lassabb lesz.
(Amúgy érdekelne egy-egy time kimenet a te/én scripted/em, illetve a sed/awk/2grep -es megvalósítások futásidejéről - ha lehet, csak hogy lássam/suk, igazak-e az elméletek :-) - de csak ha van rá lehetőség. Amúgy az awk-ra tippelném a leggyorsabb futásidőt, illetve hát nem tudom, hogy a sed nyitja/zárja-e a fájlokat - mert ha nem, akkor valszeg az verne mindent. Persze meg lehet próbálni perl-ben is )
- A hozzászóláshoz be kell jelentkezni
megejtettem a javasolt változásokat, és a a CPU terhelés megnőtt, tehát már nem az i/o vitte el a futási idő nagy részét, így a szkript már a lényeggel is tudott foglalkozni.
a sed-es változat volt persze a leggyorsabb, így ezt fogom használni. (az awk-t nem próbáltam.)
köszönöm a segítséget!
__________________________________________________________
Az életben csak egy dolog a szép, de az épp nem jut eszembe.
Slackware Linux 12.1 | 2.6.26.7-janos
- A hozzászóláshoz be kell jelentkezni
Lehet, hogy bash-ba van rá valami egyszerűbb rondaság, ez viszont megy más shell-ekben is.
Nem tudom, ez mennyire bash-specifikus, viszont szebb :-)
N="${A: -1}"
(kell a space a kettospont utan)
- A hozzászóláshoz be kell jelentkezni
hm, tényleg szebb :)
a bash a végtelen lehetőségek tárháza :)
__________________________________________________________
Az életben csak egy dolog a szép, de az épp nem jut eszembe.
Slackware Linux 12.1 | 2.6.26.7-janos
- A hozzászóláshoz be kell jelentkezni
update:
most olyan bajom van, hogy írtam egy bc szkriptet, ami egy fájlból olvassa be a számokat, read()-del és azokkal számol.
ez szép és jó, de ha a fájl végére ér, akkor már nem csinál semmit, a CPU használat pedig marad 100%-on, pedig már csak inputra vár.
hogyan tudnám ezt a helyzetet észrevenni, anélkül, hogy minden beolvasás után ki kellene írnom valamit? azért nem akarom ezt meglépni, mert a fájl 100 milliós nagyságrendű sort tartalmaz és i/o szempontból nem lenne ideális.
a kis usb rack ledjének figyelése sem biztos, hogy jó kiindulási alap.
van valakinek ötlete?
__________________________________________________________
Az életben csak egy dolog a szép, de az épp nem jut eszembe.
Slackware Linux 12.1 | 2.6.26.7-janos
- A hozzászóláshoz be kell jelentkezni
mit kellene szamolni?
tehat mi az input es hogy kene kinezni outputak?
mert lehet folosleges bc vel szorakozni, akar python akar perl vagy talan bash ben is egyszerubb megoldast talalni.
- A hozzászóláshoz be kell jelentkezni
a feladatban nagy prímekkel kell számolni, amik már nem biztos, hogy beférnek 32(/64) bites egészekbe. ezért használom a bc-t.
__________________________________________________________
Az életben csak egy dolog a szép, de az épp nem jut eszembe.
Slackware Linux 12.1 | 2.6.26.7-janos
- A hozzászóláshoz be kell jelentkezni
#!/bin/bash -x
INPUT="$1"
OUTPUT="$2"
BAD="$3"
#INPUT="input"
#OUTPUT="output"
#BAD="bad"
grep "[1379]$" < "$INPUT" > "$OUTPUT"
grep -v "[1379]$" < "$INPUT" > "$BAD"
- A hozzászóláshoz be kell jelentkezni
#!/bin/bash -x
INPUT="$1"
OUTPUT="$2"
BAD="$3"
#INPUT="input"
#OUTPUT="output"
#BAD="bad"
exec 7>&1
exec >"$OUTPUT"
exec 3>"$BAD"
for i in $( cat - )
do
echo $i | grep "[1379]$" || echo $i >&3
done < "$INPUT"
exec 1>&7 7>&-
exec 3>&-
----
de csak ha mindenaron ciklusokkal meg mindenfele sallangal kell megcsinalni. csak ertelmetlen - szerintem -
- A hozzászóláshoz be kell jelentkezni