Effizient mehrere Zeichen ausgeben

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Benutzeravatar
heinz
Beiträge: 535
Registriert: 20.12.2007 01:43:49

Effizient mehrere Zeichen ausgeben

Beitrag von heinz » 08.05.2019 19:52:01

Hallo Zusammen,

ich weiss, ich bin verrueckt, also bitte keine Fragen zur Sinnhaftigkeit... ;-)

Ich bin auf der Suche nach der effizientesten Methode um auf der Konsole mehrere gleiche Zeichen hintereinander zu erzeugen.
Natuerlich nur mit "Bordmitteln".

Testbedingungen:
100000 mal das Zeichen >#< ausgeben. (Hintereinander. Keine weiteren Zeichen!)
( 100000 um einigermassen sinnvolle Zeiten zu bekommen. )
Habe jeden Test ca. 20 mal Durchlaufen lassen um aussagekraeftigere Zeiten zu bekommen.


Meine Bisherigsten Ergebnisse:

Platz 1: (bis jetzt...)

Code: Alles auswählen

time yes \#|head -n 100000|tr -d '\n'

real 0.014 - 0.028s
user 0.000 - 0.008s
sys  0.000 - 0.012s

Platz 2:

Code: Alles auswählen

time yes \#|tr -d '\n'|dd bs=1 count=100000

real 0.027 - 0.039s
user 0.000 - 0.004s
sys  0.008 - 0.024s

Platz 3:

Code: Alles auswählen

time seq -s '#' 0 100000|tr -d '[:digit:]'

real 0.048 - 0.060s
user 0.048 - 0.058s
sys  0.000 - 0.004s

Platz 4:

Code: Alles auswählen

time echo "for(a=0;a<100000;a++)print \"#\""|bc|tr -d '[:space:]\'

real 0.069 - 0.086
user 0.048 - 0.020
sys  0.036 - 0.100

Platz 5:

Code: Alles auswählen

time echo -n {1..100000}"#"|tr -d '[:digit:][:space:]'

real 0.195 - 0.208s
user 0.168 - 0.208s
sys  0.004 - 0.028s

Platz 6: (langsamer gehts wohl kaum...)

Code: Alles auswählen

time for tt in {1..100000};do echo -n '#';done

real 0.735 - 0.774s
user 0.396 - 0.476s
sys  0.128 - 0.200s

Kennt jemand effizientere/schnellere Methoden?
(Der Code wuerde mir reichen, die Zeit-Tests kann ich selbst machen. Haengt ja auch von der jeweiligen Rechnergeschwindigkeit ab...)

Gruss, heinz

RobertDebiannutzer
Beiträge: 385
Registriert: 16.06.2017 09:52:36

Re: Effizient mehrere Zeiche ausgeben

Beitrag von RobertDebiannutzer » 08.05.2019 21:23:28

Zählt Perl für Dich auch zu "Bordmitteln"?

Code: Alles auswählen

perl -e 'print("#" x 100000, "\n")'

DeletedUserReAsG

Re: Effizient mehrere Zeiche ausgeben

Beitrag von DeletedUserReAsG » 08.05.2019 21:30:50

gcc zählt doch auch zu den Bordmitteln …

[scnr]

Benutzeravatar
Meillo
Moderator
Beiträge: 8813
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Effizient mehrere Zeiche ausgeben

Beitrag von Meillo » 08.05.2019 22:00:46

Was fuer eine coole Aufgabe! :THX:

Deine schnellste Loesung gefaellt mir gut, weil sie schoen einfach und verstaendlich ist. Sie ist zudem auch schnell, weil sie einfache Tools einsetzt. Wenn du schnell sein willst, musst du bei so einer Aufgaben moeglichst viel Overhead loswerden. So waere es in dem Fall z.B. viel besser, wenn yes(1) keine Newlines anhaengen wuerde. Programme, die du dir sparst, helfen auch. Noch mehr helfen aber einfache Operationen -- yes(1) ist immer einfach, head(1) ist auch einfach und tr(1) auch.

Auf was ich noch gekommen bin, ist:

Code: Alles auswählen

dd bs=1 count=100000 </dev/zero 2>/dev/null | tr \\0 \#
Das verwendet zwar das komplexere dd(1) und liest aus einem Device, ist sonst von seiner Arbeitsweise aber einfach. Ausserdem hast du diesen Ansatz bisher noch nicht.

EDIT: Viel schneller ist ``bs=100000 count=1''. ;-) Ich bin mir fast sicher, dass das gewinnen wird. Da bremst nur noch die Terminalausgabe.


Btw: Wie testest du die Zeiten denn? Da sollte man wohl viele Messungen machen, die Extremwerte weglassen und den Rest mitteln.


Ach, und machen wir nebenbei oder hinterher auch noch ein ``Wer loest es mit der kuerzesten Befehlszeile''? Biiiiiitte-biiiitte! :-D
Use ed once in a while!

RobertDebiannutzer
Beiträge: 385
Registriert: 16.06.2017 09:52:36

Re: Effizient mehrere Zeiche ausgeben

Beitrag von RobertDebiannutzer » 08.05.2019 22:41:15

Ich bin ja kein Spezialist in awk, aber das hier funktioniert:

Code: Alles auswählen

awk 'BEGIN{ while (n++ < 100000) printf "#" }'
(Laut manpage werden alle User-Variablen zu Null initialisiert.)

Und eine etwas auf Kürze geschummelte Version meines Perl-Ansatzes (welcher schnell ist!):

Code: Alles auswählen

perl -e 'print "#"x100000'
:mrgreen:

Benutzeravatar
Meillo
Moderator
Beiträge: 8813
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Effizient mehrere Zeiche ausgeben

Beitrag von Meillo » 08.05.2019 22:46:44

RobertDebiannutzer hat geschrieben: ↑ zum Beitrag ↑
08.05.2019 22:41:15
Ich bin ja kein Spezialist in awk, aber das hier funktioniert:

Code: Alles auswählen

awk 'BEGIN{ while (n++ < 100000) printf "#" }'
(Laut manpage werden alle User-Variablen zu Null initialisiert.)
Das sieht gut aus. :-)
Und eine etwas auf Kürze geschummelte Version meines Perl-Ansatzes (welcher schnell ist!):

Code: Alles auswählen

perl -e 'print "#"x100000'
:mrgreen:
Hmm, da wird's schwierig werden, noch kuerzer zu werden ...
Use ed once in a while!

tobo
Beiträge: 1990
Registriert: 10.12.2008 10:51:41

Re: Effizient mehrere Zeiche ausgeben

Beitrag von tobo » 08.05.2019 23:05:32

kürzer:

Code: Alles auswählen

printf %.s# {1..100000}

JTH
Moderator
Beiträge: 3023
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: Effizient mehrere Zeiche ausgeben

Beitrag von JTH » 08.05.2019 23:27:56

niemand hat geschrieben: ↑ zum Beitrag ↑
08.05.2019 21:30:50
gcc zählt doch auch zu den Bordmitteln …
Kurz wird das als Einzeiler nicht :D

Code: Alles auswählen

f=$(mktemp); gcc -xc -o$f - <<<$'#include <stdio.h>\nint main() { for (int i = 0; i != 100000; ++i) { printf("#"); } }'; $f
Die reine Ausgabe natürlich schnell

Code: Alles auswählen

$ f=$(mktemp); gcc -xc -o$f - <<<$'#include <stdio.h>\nint main() { for (int i = 0; i != 10000; ++i) { printf(\"#\"); } }'; time $f

real	0m0,006s
user	0m0,005s
sys	0m0,000s
Das Ganze eher nicht so

Code: Alles auswählen

$ time (f=$(mktemp); gcc -xc -o$f - <<<$'#include <stdio.h>\nint main() { for (int i = 0; i != 10000; ++i) { printf(\"#\"); } }'; $f)

real	0m0,061s
user	0m0,033s
sys	0m0,028s

Man kann natürlich für die Kürze ein paar Warnungen in Kauf nehmen

Code: Alles auswählen

f=$(mktemp); gcc -xc -o$f - <<<'main() { for (int i = 0; i != 100000; ++i) { printf("#"); } }'; $f

Unsinnig, aber konnte nicht widerstehen.
Manchmal bekannt als Just (another) Terminal Hacker.

Benutzeravatar
Meillo
Moderator
Beiträge: 8813
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Effizient mehrere Zeiche ausgeben

Beitrag von Meillo » 08.05.2019 23:51:50

@tobo: :-D

JTH hat geschrieben: ↑ zum Beitrag ↑
08.05.2019 23:27:56
niemand hat geschrieben: ↑ zum Beitrag ↑
08.05.2019 21:30:50
gcc zählt doch auch zu den Bordmitteln …
Kurz wird das als Einzeiler nicht :D
Warum denn nicht? Das laeuft bei mir (ohne Warnings):

Code: Alles auswählen

gcc -xc -<<<"main(){int i=100000;while(i--)putchar('#');}";./a.out
(66 Zeichen) ... nicht so toll wie tobos Vorschlag, aber trotz C recht kurz.

... korrekterweise muesste man wohl noch ein ``;rm a.out'' ans Ende setzen.

Btw: Ist zwar kein Standardtool, aber der tcc(1) kann C-Code auch interpraetieren. Damit koennte man sich die `a.out' sparen.
Use ed once in a while!

Benutzeravatar
Meillo
Moderator
Beiträge: 8813
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Effizient mehrere Zeiche ausgeben

Beitrag von Meillo » 09.05.2019 00:08:55

Meillo hat geschrieben: ↑ zum Beitrag ↑
08.05.2019 22:00:46
EDIT: Viel schneller ist ``bs=100000 count=1''. ;-) Ich bin mir fast sicher, dass das gewinnen wird. Da bremst nur noch die Terminalausgabe.
Ich frage mich gerade, ob die Zeit fuer die Terminalausgabe konstant ist. Es ist ja immer der gleiche Ausgabetext, aber gibt es Zeitunterschiede, ob ich die Zeichen nacheinander oder geblockt ausgebe? Wird es wieder langsamer, wenn der Block zu gross wird?

Eliminieren kann man die Terminalausgabe ja einfach, indem man nach /dev/null pipt. Unterscheiden sich dann die Ergebnisse relativ zueinander?
Use ed once in a while!

RobertDebiannutzer
Beiträge: 385
Registriert: 16.06.2017 09:52:36

Re: Effizient mehrere Zeichen ausgeben

Beitrag von RobertDebiannutzer » 09.05.2019 09:55:51

@meillo:
Grundsätzliches gibt es ja drei Arten von buffering (vgl. manpage setbuf: https://manpages.debian.org/stretch/man ... .3.en.html):
1. unbuffered - Zeichen werden direkt einzeln übertragen
2. line buffered - der Output erfolgt Zeile für Zeile. Der Puffer hat allerdings eine bestimmte Größe (standardmäßig BUFSIZ) - wird diese überschritten, erfolgt der Output vor dem Ende der Zeile. Das glaube ich jedenfalls, aus der manpage wird das nicht klar. Alles andere scheint mir allerdings keinen Sinn zu ergeben, denn wenn Du einen eigenen Buffer angibst, der (wie im Beispiel unten auf der manpage) stack allocated ist, kann der ja nicht mit realloc() verändert werden.
3. block buffered - der Output erfolgt in Blocks einer festgelegten Größe. Standardmäßig ist das BUFSIZ.

Standardmäßig sind Terminal-Ausgaben line buffered. Doch daran wird sich dd vermutlich nicht halten, sondern den Terminal-Buffer auf block buffered umstellen. Vermute ich jedenfalls, da Du ja mit der Option "bs=" die Größe des block buffers festlegst. Somit gilt natürlich auch nicht mehr BUFSIZ als Größe für den Buffer.
Somit erscheint es mir so, dass die Terminal-Ausgabe umso schneller wird, je größer der Buffer ist. Denn je größer der Buffer, desto weniger write() syscalls. Die Grenze scheint mir allerdings dann erreicht zu sein, wenn die Größe des sog. "page caches" erreicht ist. Hier komme ich allerdings auch an eine Grenze, nämlich an die meines momentanen Wissens... :wink:

JTH
Moderator
Beiträge: 3023
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: Effizient mehrere Zeiche ausgeben

Beitrag von JTH » 09.05.2019 11:00:23

Meillo hat geschrieben: ↑ zum Beitrag ↑
08.05.2019 23:51:50
Warum denn nicht?
Stimmt. An putchar() und a.out hab ich gar nicht mehr gedacht :oops:

Aber du bekommst nicht die zu erwartende Warnung zu impliziten Returntype und Funktionsdeklaration?
Manchmal bekannt als Just (another) Terminal Hacker.

Benutzeravatar
Meillo
Moderator
Beiträge: 8813
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Effizient mehrere Zeiche ausgeben

Beitrag von Meillo » 09.05.2019 11:17:56

JTH hat geschrieben: ↑ zum Beitrag ↑
09.05.2019 11:00:23
Aber du bekommst nicht die zu erwartende Warnung zu impliziten Returntype und Funktionsdeklaration?
Etwas provokant getfragt: Sind die denn zu erwarten? ;-)

Nein, ich bekomme sie nicht. Das koennte an irgendwelchen Defaulteinstellungen der jeweiligen GCC-Version liegen. Dennoch: Alle von mir verwendeten Funktionen geben einen `int' zurueck und das ist der Standard, darum muss man den nicht angeben. (In Pre-ANSI-C hat man den Returntyp nur dann angegeben, wenn er nicht `int' war. Das ist im Standard wohl immer noch erlaubt (... koennte man mal nachlesen).) Wenn ich printf(3) verwende meckert er schon, aber getchar(3) scheint er zu kennen. Woher dieser Unterschied kommt, weiss ich nicht auswendig (und bin gerade zu faul dem nachzugehen). Vielleicht weil das Argument von getchar(3) auch `int' ist und kein `char*' plus varargs bei printf(3)?
Use ed once in a while!

JTH
Moderator
Beiträge: 3023
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: Effizient mehrere Zeichen ausgeben

Beitrag von JTH » 09.05.2019 12:11:52

Meillo hat geschrieben: ↑ zum Beitrag ↑
09.05.2019 11:17:56
Sind die denn zu erwarten? ;-)
Ich ahne ja nicht, das dein Compiler dieses Jahr 30. feiert :wink: Und bin wohl zu viel im C++-Umfeld unterwegs …

Beides (impliziter Returntyp int und impliziter Funktionsprototyp) war wohl mit ANSI/C89 noch erlaubt. Und der GCC hat anscheinend erst seit 5.x -std=c99 als Default, also ab Stretch.
Manchmal bekannt als Just (another) Terminal Hacker.

Benutzeravatar
Meillo
Moderator
Beiträge: 8813
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Effizient mehrere Zeichen ausgeben

Beitrag von Meillo » 09.05.2019 12:27:54

JTH hat geschrieben: ↑ zum Beitrag ↑
09.05.2019 12:11:52
Meillo hat geschrieben: ↑ zum Beitrag ↑
09.05.2019 11:17:56
Sind die denn zu erwarten? ;-)
Ich ahne ja nicht, das dein Compiler dieses Jahr 30. feiert :wink: Und bin wohl zu viel im C++-Umfeld unterwegs …

Beides (impliziter Returntyp int und impliziter Funktionsprototyp) war wohl mit ANSI/C89 noch erlaubt. Und der GCC hat anscheinend erst seit 5.x -std=c99 als Default, also ab Stretch.
Das erklaert manches. Mein GCC ist noch ein 4er.

Ich lebe auch (fast) nur in der C89-Welt mit einem weit groesseren Interesse fuer K&R-C als fuer C99. (Was aber nicht aussagen soll, dass die lockeren und impliziten Regeln der alten C-Varianten guten Code foerdern wuerden!) (C99 ist fuer mich halt immer noch die Zukunft ... Ich weiss nicht recht, was ich davon halten soll, jetzt wo ich mir das bewusst mache. :-D )
Use ed once in a while!

JTH
Moderator
Beiträge: 3023
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: Effizient mehrere Zeichen ausgeben

Beitrag von JTH » 09.05.2019 13:13:51

Meillo hat geschrieben: ↑ zum Beitrag ↑
09.05.2019 12:27:54
[…] impliziten Regeln der alten C-Varianten […]
Ganz strenggenommen fehlt der C89-Variante noch ein return 0; in main(). Das ist mein ich umgekehrt erst ab C99 implizit, wenn ausgelassen. Aber genug Standard gewälzt :)
Manchmal bekannt als Just (another) Terminal Hacker.

Benutzeravatar
Meillo
Moderator
Beiträge: 8813
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Effizient mehrere Zeichen ausgeben

Beitrag von Meillo » 09.05.2019 13:28:05

JTH hat geschrieben: ↑ zum Beitrag ↑
09.05.2019 13:13:51
Meillo hat geschrieben: ↑ zum Beitrag ↑
09.05.2019 12:27:54
[…] impliziten Regeln der alten C-Varianten […]
Ganz strenggenommen fehlt der C89-Variante noch ein return 0; in main(). Das ist mein ich umgekehrt erst ab C99 implizit, wenn ausgelassen. Aber genug Standard gewälzt :)
Darum habe ich ``-pedantic'' weggelassen. :-P

Aber ja, genug des Geplaenkels ... eigentlich warten doch alle bloss auf heinz. ;-)
Use ed once in a while!

Benutzeravatar
heinz
Beiträge: 535
Registriert: 20.12.2007 01:43:49

Re: Effizient mehrere Zeichen ausgeben

Beitrag von heinz » 09.05.2019 23:33:13

Klasse! Ich bin sehr froh, nicht der einzige verrueckte hier zu sein... ;-) (Ich liebe dieses Forum...)

Vielen Dank erstmal fuer die sehr kreativen Vorschlaege!
niemand hat geschrieben: ↑ zum Beitrag ↑
08.05.2019 21:30:50
gcc zählt doch auch zu den Bordmitteln …
Naja, da hast Du sicher recht. Habe auch ein kleines C-Programm dafuer geschrieben aber es dann wieder verworfen.
In scripten moechte lieber keine Programme verwenden die auf einem anderen System erst "gebaut" werden muessen.

Wobei ich zugeben muss, der Einzeiler von JTH ist echt super! Ich waere nie auf die Idee gekommen gcc so zu benutzen.

Meillo hat geschrieben: ↑ zum Beitrag ↑
08.05.2019 22:00:46
Viel schneller ist ``bs=100000 count=1''. ;-) Ich bin mir fast sicher, dass das gewinnen wird. Da bremst nur noch die Terminalausgabe.
Du hast recht und das gibt dann auch den neuen Platz 1!
Meillo hat geschrieben: ↑ zum Beitrag ↑
08.05.2019 22:00:46
Btw: Wie testest du die Zeiten denn? Da sollte man wohl viele Messungen machen, die Extremwerte weglassen und den Rest mitteln.
Ich lasse es so ca. 20 mal laufen und merke mir die hoechsten und niedrigsten Werte.
Die Extremwerte lasse ich natuerlich weg aber mitteln tu ich nicht...
(vlt. sollte ich dafuer ein kleines Script schreiben... Mal schauen wie ich lustig bin...)


Hier nun die neuen Testergebnisse:

Platz 1 (Tipp von Meillo)

Code: Alles auswählen

time yes \#|tr -d '\n'|dd bs=100000 count=1

real 0.006 - 0.015
user 0.000 - 0.000
sys  0.000 - 0.004
Wobei ich nicht verstehe, warum

Code: Alles auswählen

dd bs=1 count=100000 </dev/zero 2>/dev/null | tr \\0 \#
langsamer ist?


Platz 2 (RobertDebiannutzer) (scheint gleichschnell zu sein wie der vorherige Platz 1)

Code: Alles auswählen

perl -e 'print "#"x100000'
oder
perl -e 'print "#"x100000'

real 0.017 - 0.026
user 0.000 - 0.004
sys  0.000 - 0.004
Platz 3 (RobertDebiannutzer) (knapp aber hoehere Werte bei user)

Code: Alles auswählen

awk 'BEGIN{ while (n++ < 100000) printf "#" }' 

real 0.018 - 0.021
user 0.004 - 0.016
sys  0.000 - 0.004
Platz 4 (Meillo) (etwas besser als der vorherige Platz 3)

Code: Alles auswählen

dd bs=1 count=100000 </dev/zero 2>/dev/null | tr \\0 \#

real 0.047 - 0.063
user 0.004 - 0.024
sys  0.072 - 0.104
Platz 5 (tobo)

Code: Alles auswählen

printf %.s# {1..100000}

real 0.177 - 0.187
user 0.160 - 0.172
sys  0.000 - 0.004
Ist irgendwie auch seltsam. Warum ist das so langsam?

Nochmals vielen Dank Euch allen!
Meillo hat geschrieben: ↑ zum Beitrag ↑
08.05.2019 22:00:46
Ach, und machen wir nebenbei oder hinterher auch noch ein ``Wer loest es mit der kuerzesten Befehlszeile''? Biiiiiitte-biiiitte! :-D
*Lach*, aber da wird wohl schon tobo gewonnen haben. Ich denke kuerzer als:

Code: Alles auswählen

printf %.s# {1..100000}
wird wohl nicht moeglich sein... (Schade das es so langsam ist.)

Viele Gruesse, heinz

Benutzeravatar
hikaru
Moderator
Beiträge: 13585
Registriert: 09.04.2008 12:48:59

Re: Effizient mehrere Zeichen ausgeben

Beitrag von hikaru » 10.05.2019 00:55:03

Vielleicht nicht effizient, aber Brainfuck [1]:

Code: Alles auswählen

--[------->++<]>-
>++++++++++[
 >++++++++++[
  >++++++++++[
   >++++++++++[
    <<<<.>>>>
   -]<
  -]<
 -]<
-]
Natürlich ist das nicht auf meinem Mist gewachsen. Ich hab's nur mühselig zusamengestückelt.
- # von [2]
- Idee für die Schleife von [3]
- Test auf [4] (lässt sich lokal vermutlich durch Debianhsbrainfuck ersetzen)

Sollte Assembler nicht schnell sein?


[1] https://de.wikipedia.org/wiki/Brainfuck
[2] https://copy.sh/brainfuck/text.html
[3] https://stackoverflow.com/questions/454 ... print-loop
[4] https://copy.sh/brainfuck/

Benutzeravatar
Meillo
Moderator
Beiträge: 8813
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Effizient mehrere Zeichen ausgeben

Beitrag von Meillo » 10.05.2019 08:18:30

heinz hat geschrieben: ↑ zum Beitrag ↑
09.05.2019 23:33:13
Klasse! Ich bin sehr froh, nicht der einzige verrueckte hier zu sein... ;-) (Ich liebe dieses Forum...)
:-)
Ich lasse es so ca. 20 mal laufen und merke mir die hoechsten und niedrigsten Werte.
Die Extremwerte lasse ich natuerlich weg aber mitteln tu ich nicht...
(vlt. sollte ich dafuer ein kleines Script schreiben... Mal schauen wie ich lustig bin...)
Kannst dir ja mal ueberlegen, ob rueckblickend das Schreiben eines Scriptes nicht schneller gewesen waere als all die manuellen Programmaufrufe, die du bisher gemacht hast. Der Vorteil am Script ist, dass du zum einen, falls du einen Fehler im Vorgehen entdeckst, einfach alle Tests nochmal laufen lassen kannst, und zum zweiten, dass es keinen Mehraufwand verursacht, wenn du statt 20 lieber 200 Durchlaeufe machen willst.

Hier nun die neuen Testergebnisse:

Platz 1 (Tipp von Meillo)

Code: Alles auswählen

time yes \#|tr -d '\n'|dd bs=100000 count=1

real 0.006 - 0.015
user 0.000 - 0.000
sys  0.000 - 0.004
Da stimmt die Codezeile noch nicht, oder haben wir uns falsch verstanden?

Ich denke, am schnellsten waere:

Code: Alles auswählen

dd bs=100000 count=1 </dev/zero 2>/dev/null | tr \\0 \#
... und nicht eine Variante mit yes(1).
Wobei ich nicht verstehe, warum

Code: Alles auswählen

dd bs=1 count=100000 </dev/zero 2>/dev/null | tr \\0 \#
langsamer ist?
`bs=1 count=100000' liest 100.000 Mal ein Byte, waehrend `bs=100000 count=1' ein Mal 100.000 Bytes liest. Der ganze Leseoverhead (Festplatten-Seek & Co.) sind dann nur einmal und nicht potenziell 100.000 Mal vorhanden.

Das ist wie wenn du aus einem Buch 100.000 Zeichen am Stueck liest, im Gegensatz dazu, das Buch aufzuschlagen, ein Zeichen zu lesen, es zuzuschlagen, es wieder aufzuschlagen, die Stelle zu finden, das naechste Zeichen zu lesen, es wieder zuzuschlagen, usw.

Platz 5 (tobo)

Code: Alles auswählen

printf %.s# {1..100000}

real 0.177 - 0.187
user 0.160 - 0.172
sys  0.000 - 0.004
Ist irgendwie auch seltsam. Warum ist das so langsam?
Weil die Shell hier bei der Brace-Expansion eine riesig lange Befehlszeile erzeugen muss, die sicherlich mehrere realloc(3)s benoetigt und vielleicht noch weiteren Overhead erzeugt. Das printf(1) (oder das Shell-Builtin printf?) muss dann fuer seinen Output-Buffer wieder mehrmals Reallozieren. Da wird also immer wieder im Speicher rumkopiert. Das wird es vermutlich langsam machen.
Meillo hat geschrieben: ↑ zum Beitrag ↑
08.05.2019 22:00:46
Ach, und machen wir nebenbei oder hinterher auch noch ein ``Wer loest es mit der kuerzesten Befehlszeile''? Biiiiiitte-biiiitte! :-D
*Lach*, aber da wird wohl schon tobo gewonnen haben. Ich denke kuerzer als:

Code: Alles auswählen

printf %.s# {1..100000}
wird wohl nicht moeglich sein... (Schade das es so langsam ist.)
Das scheint mir auch so zu sein. Auch die Umsetzung in C wird wohl kaum noch kuerzer gehen. (Das letzte Mal, als ich so eine Vermutung geaeussert habe, hat tobo direkt eine kuerzere Version gepostet ... vielleicht klappt das dieses Mal wieder. ;-) )
Use ed once in a while!

RobertDebiannutzer
Beiträge: 385
Registriert: 16.06.2017 09:52:36

Re: Effizient mehrere Zeichen ausgeben

Beitrag von RobertDebiannutzer » 10.05.2019 09:46:50

"Brainfuck" kann ich auch... :mrgreen:

Code: Alles auswählen

str="" && while [ $(wc -m <<< $str) -lt 100000 ]; do str+=$(openssl rand 100000 | grep -o --text '#' | tr -d '\n'); done && printf $str
(Erfordert bash und openssl-rand. Die Anforderung von 100000 Zufalls-Bytes ist natürlich beliebig.) Das gibt zwar stets mehr als 100000 "#" aus, aber es waren ja auch nicht *genau* 100000 gefordert:
heinz hat geschrieben: ↑ zum Beitrag ↑
08.05.2019 19:52:01
Testbedingungen:
100000 mal das Zeichen >#< ausgeben. (Hintereinander. Keine weiteren Zeichen!)
( 100000 um einigermassen sinnvolle Zeiten zu bekommen. )
*SNCR*
Meillo hat geschrieben: ↑ zum Beitrag ↑
10.05.2019 08:18:30
(oder das Shell-Builtin printf?)
In bash (Debian stretch) ist es ein builtin. In dash auch. @heinz: Mit "type builtin" kannst Du es herausfinden, jedenfalls bei den beiden genannten Shells.

Mit gcc ging es kürzer, wenn stdio.h nicht includiert ( :wink: ) werden müsste:

Code: Alles auswählen

gcc -xc -<<<$'#include<stdio.h>\nmain(){printf("%*c",100000,\'#\');}';./a.out

Benutzeravatar
Meillo
Moderator
Beiträge: 8813
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Effizient mehrere Zeichen ausgeben

Beitrag von Meillo » 10.05.2019 10:38:17

RobertDebiannutzer hat geschrieben: ↑ zum Beitrag ↑
10.05.2019 09:46:50
Mit gcc ging es kürzer, wenn stdio.h nicht includiert ( :wink: ) werden müsste:

Code: Alles auswählen

gcc -xc -<<<$'#include<stdio.h>\nmain(){printf("%*c",100000,\'#\');}';./a.out
Hast du das getestet? Bei mir gibt das keine 100.000 Hashes aus, sondern 99.999 Spaces gefolgt von einem Hash.
Use ed once in a while!

RobertDebiannutzer
Beiträge: 385
Registriert: 16.06.2017 09:52:36

Re: Effizient mehrere Zeichen ausgeben

Beitrag von RobertDebiannutzer » 10.05.2019 10:44:52

Oh Mist!! Ja, ich habe es getestet, aber nur mit "wc -m" - der Output ging also in die Pipe zu wc und somit habe ich ihn nicht gesehen. :facepalm:
Aber ich bin mir fast sicher, dass das mit printf() irgendwie ging. Nur ich finde grad nix dazu in der manpage und suchmaschinen will ich natürlich nicht (das gilt ja nicht :wink: ).

Benutzeravatar
Meillo
Moderator
Beiträge: 8813
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Effizient mehrere Zeichen ausgeben

Beitrag von Meillo » 10.05.2019 10:57:41

RobertDebiannutzer hat geschrieben: ↑ zum Beitrag ↑
10.05.2019 10:44:52
Oh Mist!! Ja, ich habe es getestet, aber nur mit "wc -m" - der Output ging also in die Pipe zu wc und somit habe ich ihn nicht gesehen. :facepalm:
Ich arbeite einfach mit der Zahl 100 statt 100000, damit mir der Bildschirm nicht zugemuellt wird. Nur so als Tipp. ;-)
Aber ich bin mir fast sicher, dass das mit printf() irgendwie ging.
Es geht halt so wie tobo das gemacht hat, aber das erfordert 100.000 Argumente fuer printf() (die er mittels der Brace-Expansion erzeugt).
Nur ich finde grad nix dazu in der manpage und suchmaschinen will ich natürlich nicht (das gilt ja nicht :wink: ).
Ich sehe keinen Grund fuer diese Zurueckhaltung. Ich informiere mich auch an verschiedenen Stellen und lasse mich moeglichst breit inspirieren. Und falls jemand anderes eine fertige Loesung hat, greife ich die gerne auf (und wuerdige die Person dafuer).
Use ed once in a while!

RobertDebiannutzer
Beiträge: 385
Registriert: 16.06.2017 09:52:36

Re: Effizient mehrere Zeichen ausgeben

Beitrag von RobertDebiannutzer » 10.05.2019 11:46:24

In $Suchmaschine habe ich wieder gefunden, was ich meinte:
You can use the %* form of printf, which accepts a variable width. And, if you use '0' as your value to print, combined with the right-aligned text that's zero padded on the left..

Code: Alles auswählen

printf("%0*d\n", 20, 0);
produces:

Code: Alles auswählen

00000000000000000000
With my tongue firmly planted in my cheek, I offer up this little horror-show snippet of code.
Quelle: https://stackoverflow.com/questions/146 ... ing-printf
Aber das funktioniert leider nicht mit dem "#"-Zeichen. Und wäre so wie ich das verstehe auch echt hässlich... :mrgreen:

Antworten