Wie funktioniert die Objective-C-Laufzeitumgebung von Apple mit Multithreading-Referenzzählung ohne Leistungseinbußen?

8

Ich habe also diesen Artikel gelesen ein Versuch, die globale Interpreter-Sperre (GIL) aus dem Python-Interpreter zu entfernen, um die Multithreading-Leistung zu verbessern und etwas Interessantes zu sehen.

Es stellt sich heraus, dass einer der Orte, an denen das Entfernen der GIL die Dinge tatsächlich verschlimmerte, in der Speicherverwaltung lag:

  

Beim Freifädeln verlieren Referenzzählvorgänge ihre Fadensicherheit. Somit führt der Patch eine globale Referenzzähl-Mutex-Sperre zusammen mit atomaren Operationen zum Aktualisieren der Zählung ein. Unter Unix wird das Sperren mithilfe einer Standard-pthread_mutex_t-Sperre (in einer PyMutex-Struktur eingeschlossen) und den folgenden Funktionen ...

implementiert      

... Unter Unix muss betont werden, dass die einfache Referenzzählmanipulation durch nicht weniger als drei Funktionsaufrufe ersetzt wurde, plus dem Overhead der tatsächlichen Verriegelung. Es ist viel teurer ...

     

... Ein klar fein abgestuftes Sperren von Referenzzählungen ist der Hauptgrund für die schlechte Leistung, aber selbst wenn Sie die Sperre wegnehmen, ist die Referenzzählleistung immer noch sehr empfindlich gegenüber jeglichem zusätzlichen Aufwand (z. B. Funktion) Anruf usw.). In diesem Fall ist die Leistung immer noch etwa doppelt so langsam wie Python mit der GIL.

und später:

  

Die Referenzzählung ist eine wirklich miese Speicherverwaltung für Free-Threading. Dies war bereits allgemein bekannt, aber die Leistungszahlen konkretisieren es. Dies wird definitiv das schwierigste Problem für jeden sein, der einen GIL Entfernungs-Patch versucht.

Die Frage ist also, ob die Referenzzählung beim Threading so mies ist, wie geht es Objective-C? Ich habe Multithread-Objective-C-Apps geschrieben und habe keinen großen Aufwand für die Speicherverwaltung bemerkt. Tun sie etwas anderes? Wie eine Art von Objektverriegelung statt einer globalen? Ist die Referenzzählung von Objective-C tatsächlich technisch unsicher mit Threads? Ich bin nicht genug von einem Nebenläuferexperten, um wirklich viel zu spekulieren, aber ich wäre daran interessiert zu wissen.

    
Mike Akers 18.12.2012, 22:03
quelle

2 Antworten

8

Es gibt Overhead und es kann in seltenen Fällen signifikant sein (wie zum Beispiel Mikro-Benchmarks), unabhängig von den vorhandenen Optimierungen (von denen es viele gibt). Der Normalfall ist jedoch optimiert, um die Referenzzählung für das Objekt nicht zu manipulieren.

  

Die Frage ist also, ob die Referenzzählung beim Threading so mies ist, wie geht es Objective-C?

Es gibt mehrere Sperren im Spiel und effektiv eine Retain / Release für jedes Objekt wählt eine zufällige Sperre (aber immer die gleiche Sperre) für das Objekt. Auf diese Weise wird die Sperrkonkurrenz verringert, während für jedes Objekt keine Sperre erforderlich ist.

(Und was Catfish_man sagte; einige Klassen implementieren ihr eigenes Referenzzählschema, um klassenspezifische Sperrgrundelemente zu verwenden, um Konflikte zu vermeiden und / oder für ihre spezifischen Bedürfnisse zu optimieren.)

Die Implementierungsdetails sind komplexer.

  

Ist die Referenzzählung von Objectice-C tatsächlich technisch mit Threads unsicher?

Nein - es ist sicher in Bezug auf Threads.

In der Praxis ruft typischer Code retain und release im Vergleich zu anderen Operationen recht selten auf. Selbst wenn diese Codepfade einen beträchtlichen Overhead aufwiesen, würde sich dies über alle anderen Vorgänge in der App amortisieren (wenn zum Beispiel das Schieben von Pixeln auf den Bildschirm wirklich im Vergleich teuer ist).

Wenn ein Objekt über Threads hinweg geteilt wird (schlechte Idee, im Allgemeinen), dann ist der Sperr-Overhead, der den Datenzugriff und die Manipulation schützt, wegen der Seltenheit des Zurückhaltens / Freigebens im Allgemeinen viel größer als der Retain / Release-Overhead. p>

Soweit Pythons GIL-Overhead betroffen ist, würde ich wetten, dass es mehr damit zu tun hat, wie oft der Referenzzähler als Teil der normalen Interpreteroperationen inkrementiert und dekrementiert wird.

    
bbum 18.12.2012, 22:19
quelle
7

Zusätzlich zu dem, was bbum gesagt hat, überschreiben viele der am häufigsten in Cocoa umhergeworfenen Objekte die normalen Referenzzählmechanismen und speichern eine refcount inline im Objekt, die sie mit atomaren Add- und Subtract-Befehlen anstatt mit Locking manipulieren / p>

(Bearbeiten aus der Zukunft: Objective-C führt diese Optimierung jetzt automatisch auf modernen Apple-Plattformen aus, indem er den Refcount mit dem 'isa' -Zeiger mischt)

    
Catfish_Man 18.12.2012 22:35
quelle