---is---

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
BlackJack

@snafu: Das wäre eher `CBM BASIC`-Manier als `C64-Manier`. Es gibt auf dem und für den C64 durchaus Programmiersprachen und Compiler, die mehr als zwei signifikante Zeichen (+ Typ-Sigil) für Bezeichner berücksichtigen. :-)

Bei den meisten Implementierungen auf dem Originalgerät gibt es zwar auch eine harte Obergrenze, die ist mit in der Regel 16 oder 32 Zeichen deutlich programmier- bzw. lesefreundlicher angelegt.

Was die Bezeichner angeht, kann man auf dem C64 mit so ziemlich jedem Makro-Assembler lesbarere Programme schreiben als mit dem eingebauten BASIC.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

lunar hat geschrieben:
BlackJack hat geschrieben:@mutetella: Den letzten Beitrag verstehe ich nicht!?
Ich glaube, dass er sich fragt, ob die Technik, zwecks Beschleunigung bestimmte Exemplare "kleiner" Objekte vorzuhalten, so wie es bei "int" oder "str" der Fall ist, nur auf den Interpreter beschränkt ist, oder auch generell in Python-Quelltext Anwendung findet.
Genau, das meinte ich. Allerdings nicht "zwecks Beschleunigung", sondern weil es keine andere/bessere Möglichkeit gibt.
lunar hat geschrieben:mutetella, auf die Gefahr hin, mich zu wiederholen, sage ich Dir, dass es nichts wird mit Dir und Deinen Programmen, wenn Du Dich weiterhin so zwanghaft um solche Kleinigkeiten sorgst. Nichts für ungut ...
Schon klar, das ist bei mir angekommen und ich versuch' auch, rechtzeitig die Kurve zu bekommen... :) Aus Gründen der Performance den is-Operator einem == vorzuziehen war jetzt auch eher ein doofer Witz von mir.
Allerdings muss es ja einen Grund geben, weshalb Python Zahlen bis 256 bereits als Objekte vorbereitet und weitere Zahlen erst bei Bedarf erzeugt. Und ich dachte mir, dass ein Grund vielleicht auch der ist, dass Zahlen eben unendlich vorhanden sind und von daher gar nicht alle als Objekte zur Verfügung stehen können. Das nur mal als Ausgangspunkt meiner Überlegung. Performance steht dabei für mich gar nicht im Vordergrund, ehrlich!
Nachdem ich in meinem Kalenderprogramm natürlich auch mit unendlichen Ergebnissen zu tun habe, kam ich dann eben auf den Gedanken, ob das Bereitstellen einer bestimmten Anzahl von Objekten aus einer Liste unendlicher dieser Objekte eine Möglichkeit wäre, "Unendlichkeit" in den Griff zu bekommen. Neben Generatoren oder dem Prüfen bestimmter Kriterien eines Objekts.
DasIch hat geschrieben:Dir ist klar dass wir hier von Interpreter spezifischem Verhalten reden womit du allerhöchstens kaputten Code produzierst?
Wie gesagt, das war jetzt eher ein nicht ernst gemeinter Hinweis auf tief verwurzelte Performance-Phopie, die auf Zeiten zurückzuführen ist, in denen ich Stunden und Tage damit verbracht hatte, verschiedenste Kombinationen von LoadHigh (LH) Anweisungen in meiner autoexec.bat zu testen.

@snafu: Vierfache Verschachtelungstiefe ist ein toller Tipp, danke! Allerdings macht mir dieses ständige 16xLeertaste-gehacke echt Schwierigkeiten! Aber da gibt's bestimmt ein VIM-Script für. Ich google das mal...
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

mutetella hat geschrieben:@snafu: Vierfache Verschachtelungstiefe ist ein toller Tipp, danke! Allerdings macht mir dieses ständige 16xLeertaste-gehacke echt Schwierigkeiten! Aber da gibt's bestimmt ein VIM-Script für. Ich google das mal...
Du kannst vim wie jeden anderen (brauchbaren) Editor dazu einstellen Leerzeichen statt Tabs zu verwenden. Meine Python spezifischen Einstellungen findest du z.B. hier
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@DasIch: Du hast den Witz schon verstanden, oder? Und falls nicht: Sollte ich dann nicht eher Tabs statt Leerzeichen verwenden?
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

mutetella hat geschrieben:@snafu: Vierfache Verschachtelungstiefe ist ein toller Tipp, danke! Allerdings macht mir dieses ständige 16xLeertaste-gehacke echt Schwierigkeiten! Aber da gibt's bestimmt ein VIM-Script für. Ich google das mal...
Fuer den Fall, dass das ernst gemeint war:

Code: Alles auswählen

set tabstop=4, expandtab
Edit: Nein, wehe du nutzt Tabs!

Zu deiner Unendlichkeitsueberlegung: Warum soll dir das Vorhalten einer _endlichen_ Menge moeglicher Objekte bei der Handhabung einer _unendlichen_ Menge helfen?
Generatoren oder generell das Erzeugen von Objekten wenn sie denn ueberhaupt gebraucht werden, ist die einzige Moeglichkeit damit umzugehen.

Wenn du dir aufgrund deines Kaffeesatzes 10 beliebige Daten von heute bis zum Erscheinen von Duke Nukem Forever rauspickst, ist das keine Hilfe. Sind es die naechsten 10, dann ist das eine "Optimierung" mit der Annahme, dass die haeufig gebraucht werden.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

BlackJack hat geschrieben:@snafu: Das wäre eher `CBM BASIC`-Manier als `C64-Manier`. Es gibt auf dem und für den C64 durchaus Programmiersprachen und Compiler, die mehr als zwei signifikante Zeichen (+ Typ-Sigil) für Bezeichner berücksichtigen. :-)
Wobei die Betonung hier auf "berücksichtigen" liegen muss - prinzipiell konnte man auch im C64er Basic längere Variablennamen benutzen¹.


¹) Was hat mich das seinerzeit Nerven gekostet, darauf zurückzuführende Fehler zu finden :mrgreen:
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@Hyperion: Längere Namen habe ich aber nie im Einsatz gesehen, eben wegen der Probleme Fehler zu finden und weil sie unnötig Speicherplatz und auch Rechenzeit beim Programmablauf kosten. Der Interpretierer ist ja trotz Byte-Tokens für Schlüsselworte ziemlich doof und muss jedesmal die zusätzlichen Zeichen überspringen wenn er auf einen solchen "langen" Bezeichner während des Programmlaufs trifft.

Wobei "nie" stimmt nicht ganz -- ich hatte damals einmal "echte" lange Bezeichner gesehen, bei einem Programm das für die Übersetzung mit dem BASIC-Boss-Compiler vorgesehen war. Der kann nämlich auch mehr als zwei signifikante Zeichen wenn man ihn darum bittet.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

BlackJack hat geschrieben:@Hyperion: Längere Namen habe ich aber nie im Einsatz gesehen, eben wegen der Probleme Fehler zu finden und weil sie unnötig Speicherplatz und auch Rechenzeit beim Programmablauf kosten.
Ich hatte mir das auch relativ schnell abgewöhnt, nachdem ich das durchschaut hatte ;-)

Als ich dann auf dem PC zunächst C lernte, empfand ich die Freiheit bei Bezeichnern als super komfortabel :-) Vermutlich eines der wichtigsten informalen Konzepte zur Strukturierung von Programmen.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

BlackJack hat geschrieben:Wobei "nie" stimmt nicht ganz -- ich hatte damals einmal "echte" lange Bezeichner gesehen, bei einem Programm das für die Übersetzung mit dem BASIC-Boss-Compiler vorgesehen war.
Der BASIC-Boss-Compiler, ach ja. *seufz* Das war das letzte Programm das ich noch für den C=64 gekauft habe bevor ich mich dann anderen Maschinen zugewandt habe.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@mutetella:

Was der Interpreter macht, ist ja im Prinzip nichts anderes als Caching, weil man davon ausgeht, dass die ersten kleineren Zahlen besonders häufig zur Anwendung kommen. Analog dazu könnte man in einen Kalender schon beim Starten die kompletten Tage für das aktuelle und für das nächste Jahr erzeugen. Das würde dann, je nach Leistungsstärke des Rechners oder sicher spätestens als Webanwendung auf dem Server, ein bißchen Peformance bringen und wäre auch eine IMHO sinnvolle Optimierung.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@snafu:
Ja genau, in diese Richtung gingen meine Überlegungen...
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

@mutetella: Zumindest im Bezug auf GTK habe ich festgestellt, dass es sehr sinnvoll sein kann, bestehende Grafik-Objekte wiederzuverwerten / anzupassen.

Anstatt also 1.000 Tages-Widgets zu erstellen würde ich einmal 31 Stück für einen "View" generieren und dann je nach Monat ein paar Ausblenden und den Rest neu bestücken. Das unterbindet ggf. auch hässliches Flackern.

Ist jetzt natürlich alles etwas ins Blaue gesprochen, da ich deinen Code nicht kenne. Aber das mit dem Objekt-Caching hört sich schon etwas nach GUI an, weil ich mir nicht vorstellen kann, dass es so unperformant ist, 30 simple Daten-Objekte zu generieren, die vll. einen Termin und ein Datum halten. Wobei das hier vll. etwas OT geht, sorry dafür.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@Barabbas:
Ursprünglich hatte ich auch für jeden Tag ein eigenes Widget, das wiederum Einträge für Termine enthielt. Inzwischen zeichne ich eine Kalenderansicht, da das wesentlich flüssiger dargestellt wird, als bei jeder neuen (Monats-)ansicht 35 Widgets zu aktualisieren. Ein Rechteck mit ein paar Zeilen Text ist da einfach schneller gezeichnet als ein Panel, das dann auch noch in einem Sizer steckt.

Meine Überlegung ist die, dass ich eben, wie snafu auch schon sagte, alle nötigen Termine samt Wiederholungen für einen gewissen Zeitraum im voraus generiere damit das Blättern durch den Kalender möglichst flüssig läuft.

Ich arbeite mit wx, denke aber mal, dass das mit GTK nicht wesentlich anderst wäre.
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
pythonstarter
User
Beiträge: 53
Registriert: Donnerstag 15. April 2010, 20:34

:roll: Krass, was aus einer so - scheinbar - einfachen Frage alles werden kann
Werde mich in Zukunft auf einfachere Fragen beschränken, die meinem Wissensstand angemessen sind :)
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Och nö, bitte nicht. Ich finds so viel interessanter.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

pythonstarter hat geschrieben:Werde mich in Zukunft auf einfachere Fragen beschränken, ...
Ich schließe mich da 'derdon' an. Dein Thread ist doch wieder ein tolles Beispiel dafür, wie man durch Fragen und Nachhaken ein kleines Stück von der Erfahrung und dem Wissen anderer abbekommt.
Ich stehe auch noch ziemlich am Anfang und denke oft, dass meine Fragen hier viel Kopfschütteln hervorrufen... :-) Wenn ich aber ein Tutorial durchgearbeitet oder mich in ein Thema eingelesen hab', sind es meistens Antworten auf meine einfachen und naiven Fragen, die vieles plötzlich klar werden lassen.

Also bitte: Weiterfragen, auch wenn's noch so ... erscheint!
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
pythonstarter
User
Beiträge: 53
Registriert: Donnerstag 15. April 2010, 20:34

:idea: Stimmt :idea:
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

(das wird jetzt OT, aber ich hatte gerade Lust dazu...)

Ist `is` schneller als `==`? Generell ja, aber die beiden Operationen haben verschiedene Aufgaben und es wäre, als wenn man fragen würde, ob Addition wohl schneller ist als Multiplikation (was in der Regel auch zutrifft).

Warum werden bei CPython bestimmte Zahlenobjekte vorinitialisiert? Das ist eine Performance-Optimierung aufgrund der konkreten Objektrepräsentation von CPython. Ich schreibe extra CPython, da dies eine Design-Entscheidung dieses konkreten Interpreters ist und nicht eine Eigenschaft der Sprache Python.

Wenn man Python-Objekte im Speicher repräsentieren will, wählt man meist den "tagged values"-Ansatz, d.h. jedem Stück Speicher, in dem die Bit-Repräsentation des Objekts steht, ist ein "tag", eine Markierung vorausgestellt, die angibt, was die Bits bedeuten. So könnte eine 1 für "int", eine 2 für "str", eine 3 für "type" usw. stehen. Eine alternative Repräsentation wären tagged pointers, aber AFAIK nutzt die kaum eine Sprache, auch wenn das bei 64-bit-Maschinen möglicherweise effizienter wäre. Bei 32-bit-Maschinen sind jedoch tagged values besser.

In C könnte das (mein C ist eingerostet, daher lege ich keinen Finger ins Feuer) so aussehen:

Code: Alles auswählen

    struct tagged_val {
        int tag;
        union {
            int i;
            char s[0];
            ...
        } val;
    };
    
    typedef struct tagged_val *VALUE;
Will ich nun eine Zahl "42" anlegen, hilft mir die folgende Funktion, den für "tag" und "val" notwendigen Speicher zu reservieren und zu initialisieren und liefert mit ein "VALUE" - also einen Zeiger auf den Speicherbereich zurück.

Code: Alles auswählen

    VALUE make_int(int i) {
        VALUE v = alloc(sizeof(int) + sizeof(int));
        v->tag = 1;
        v->val.i = i;
        return v;
    }

Für Strings funktioniert das analog.

Code: Alles auswählen

    VALUE make_str(char *s) {
        VALUE v = alloc(sizeof(int) + sizeof(char) * (strlen(s) + 1));
        v->tag = 2;
        strcpy(&v->val.s, s);
        return v;
    }

Will ich prüfen, ob ein "VALUE" ein "int" oder ein "str" ist, kann ich dafür passende Funktionen in C zur Verfügnug stellen:

Code: Alles auswählen

    int is_int(VALUE v) {
        return v->tag == 1;
    }
    
    int is_str(VALUE v) {
        return v->tag == 2;
    }
Nun kann ich zwei Zahlen addieren, indem ich sicherstelle, dass es überhaupt Objekte vom Typ "int" sind, dann deren "val" auslese, in C die Addition auf C-"int" durchführe und dann wieder ein "int"-VALUE erzeuge.

Code: Alles auswählen

    VALUE add(VALUE a, VALUE b) {
        assert(is_int(a) && is_int(b));
        return make_int(a->val.i + b->val.i);
    }
Man erkennt, dass jetzt alle Rechenoperationen mit neuen Zahlenobjekten nur so um sich schmeißen und deren Speicher muss verwaltet werden. Ein simpler Garbage-Collection-Algorithmus (oder das noch primitivere Referenzenzählen von CPython) sind damit schnell überfordert und die Performance des Systems bricht ein. Daher hält CPython für die häufig verwendeten Zahlen die Objekte schon vor, um nicht jedes Mal deren Speicher neu anzufordern, Referenzen zu zählen und den Speicher dann wieder freizugeben.

Eine typische Optimierung, die CPython nicht macht, wäre bestimmte häufig vorkommende Objekttypen wie z.B. "int" durch sogenannte "immediate values" zu repräsentieren, dass sind verkappte Zeiger, die auf gar nichts zeigen, sondern wo die Bitrepräsentation des Zeigers als Wert interpretiert wird. Dabei wird ausgenutzt, dass Zeiger meist nur auf gerade Speicheradressen oder auf Adressen, die durch 4 oder 8 teilbar sind zeigen. Das dies immer zutrifft, kann man in "alloc" zusichern. Wenn Adressen z.B immer gerade sind, ist das unterste Bit immer 0. Trifft der Interpreter auf einen Zeiger, dessen unterstes Bit gesetzt ist, kann eine Sonderbehandlung stattfinden und die restlichen 31 oder 63 Bits können als Integer-Zahl interpretiert werden.

Das sieht dann so in C aus:

Code: Alles auswählen

    typedef void *VALUE;
    
    VALUE make_int(int i) {
        return (VALUE) i << 1 + 1;
    }
    
    VALUE make_str(char *s) {
        struct tagged_val *tv = alloc(sizeof(int) + sizeof(char) * (strlen(s) + 1));
        tv->tag = 1;
        strcpy(&tv->val.s, s);
        return (VALUE) tv;
    }
    
    int is_int(VALUE v) {
        return ((int) v) & 1;
    }
    
    int is_str(VALUE v) {
        return !is_int(v) && ((struct tagged_val *) v)->tag == 1;
    }
Nun kann man mit Zahlen deutlich effizienter operieren und sie verbrauchen niemals Speicher, der mit "alloc" reserviert und dann vom Garbage Collector verwaltet werden muss.

Code: Alles auswählen

    VALUE add(VALUE a, VALUE b) {
        assert(is_int(a) && is_int(b));
        return (VALUE) (((int) a) - 1 + ((int) b));
    }
Noch besser wäre, wenn man Zahlen nicht mit gesetztem untersten Bit repräsentiert, sondern anders herum, bei Zahlen das unterste Bit gelöscht hat und bei allen Zeigern dafür das unterste Bit setzt. Bei den alten SPARC-Prozessoren war das AFAIK egal, dort mussten sowieso die Adressen durch 4 teilbar sein und die CPU hat die untersten beiden Bit daher ignoriert - genau um dort derartige eingebettete "tags" eintragen zu können. Das hat frühe Lisp-Systeme auf SPARC deutlich effizienter gemacht als auf dem 6800er (Intel hatte zu der Zeit noch eine nennenswerten CPUs im Angebot). Inzwischen ist alles Intel-dominiert und ich weiß nicht, ob dort irgendwelche Tricks funktionieren. Hinzu kommt, dass man Interpreter für Sprachen nicht mehr in Assembler schreibt, sondern in C (oder in einer Hochsprache) und gewisse Low-Level-Operationen noch nicht einmal portabel in C beschreibbar sind und man daher in der Regel darauf verzichtet.

Reserviert man eines von 32 Bits für ein "immediate"-Flag, können Zahlen natürlich nur noch 31 Bits für ihre Repräsentation haben und man kann nur noch -1073741824 bis +1073741823 effizient darstellen. Nutzt man 2 bits, weil man z.B. Wahrheitswerte, Buchstaben, Symbole, Cons-Zellen oder andere häufige Datentypen auch noch effizient darstellen will, schrumpft der Zahlenbereich weiter. Ich vermute, daher hat man sich bei Python gegen diese Repräsentation entschieden. Zur Geburtsstunde der Sprache hatten die Maschinen ja eher 16-Bit-CPUs, sodass die Zahlen richtig klein geworden wären.

Im Zeitalter von 64-Bit denke ich allerdings, dass man sich locker 8 oder 16 ganz oben in den Adressen als tag gönnen könnte, weil auch 48-Bit noch einen ausreichend großen Adressraum beschreiben würden.

Stefan
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Wow, danke sma

Hat das einen Grund warum die alloc genommen hast anstatt von malloc? alloc ist doch afair Compiler-spezifisch und reserviert Speicher vom Stack, nicht wie malloc vom Heap.

//Edit: alloca reserviert vom Stack, alloc existiert nicht
the more they change the more they stay the same
Antworten