Die Leistungskosten für die Verwendung von ref, anstatt die gleichen Typen zurückzugeben?

9

Hi, das ist etwas, was mich wirklich stört und ich hoffe, dass jemand eine Antwort für mich hat. Ich habe über ref (und out ) gelesen und versuche herauszufinden, ob ich meinen Code mit ref s verlangsame. Gewöhnlich werde ich etwas ersetzen wie:

%Vor%

mit

%Vor%

weil für meine Augen das

%Vor%

ist einfacher zu lesen UND-Code als das

%Vor%

Ich weiß genau, was ich mit ref am Code mache, im Gegensatz zur Rückgabe eines Wertes. Leistung ist jedoch etwas, was ich ernst nehme, und offensichtlich Dereferenzierung und Aufräumen ist viel langsamer, wenn Sie Refs verwenden.

Was ich gerne wissen würde, ist warum jeder Beitrag, den ich lese, sagt, dass es sehr wenige Orte gibt, an denen du normalerweise ref weitergeben würdest (ich weiß, dass die Beispiele erfunden sind, aber ich hoffe du bekommst die Idee), wenn es mir scheint, dass das ref Beispiel kleiner, sauberer und genauer ist.

Ich würde auch gerne wissen, warum ref wirklich langsamer ist, als einen Werttyp zurückzugeben - mir würde es scheinen, wenn ich den Funktionswert viel bearbeiten würde, bevor ich ihn zurücksende, wäre es das schneller auf die aktuelle Variable zu verweisen, um sie zu bearbeiten, im Gegensatz zu einer Instanz dieser Variablen, kurz bevor sie aus dem Speicher gelöscht wird.

    
user1044057 13.11.2011, 10:37
quelle

4 Antworten

11

Die Hauptzeit, in der "ref" in derselben Weise wie Leistung verwendet wird, ist die Diskussion einiger sehr atypischer Fälle, zum Beispiel in XNA-Szenarien, in denen das Spiel "Objekte" eher durch Strukturen als durch Klassen repräsentiert wird, um Probleme zu vermeiden GC (die einen unverhältnismäßigen Einfluss auf XNA hat). Dies wird nützlich für:

  • verhindert das mehrfache Kopieren einer übergroßen Struktur auf dem Stapel
  • verhindert den Datenverlust aufgrund der Mutation einer Strukturkopie (XNA-Strukturen sind im Gegensatz zur normalen Praxis häufig veränderbar)
  • erlaubt das Übergeben einer Struktur in einem Array direkt , anstatt sie in
  • zu kopieren und wieder zurück zu kopieren

In allen anderen Fällen ist "ref" häufiger mit einem zusätzlichen Nebeneffekt verbunden, der im Rückgabewert nicht einfach ausgedrückt werden kann (siehe z. B. Monitor.TryEnter).

Wenn Sie kein Szenario wie XNA / struct haben und es keinen peinlichen Nebeneffekt gibt, dann verwenden Sie einfach den Rückgabewert. Abgesehen davon, dass es typischer ist (was an und für sich einen Wert hat), könnte es durchaus weniger Daten weitergeben (und int ist kleiner als ein Verweis auf x64) und könnte weniger Dereferenzierung erfordern.

Schließlich ist der Rückkehransatz vielseitiger; Sie möchten nicht immer die Quelle aktualisieren. Kontrast:

%Vor%

Ich denke, die letzte ist die am wenigsten klare (mit der anderen "ref" eine dicht dahinter) und Ref-Nutzung ist noch weniger klar in Sprachen, wo es nicht explizit ist (VB zum Beispiel).

    
Marc Gravell 13.11.2011, 11:00
quelle
3

Der Hauptzweck der Verwendung des Schlüsselworts ref besteht darin, anzuzeigen, dass der Wert der Variablen durch die Funktion geändert werden kann, in die sie übergeben wird. Wenn Sie eine Variable nach Wert übergeben, wirken sich Aktualisierungen innerhalb der Funktion nicht auf die Originalkopie aus.

Es ist äußerst nützlich (und schneller) für Situationen, in denen mehrere Rückgabewerte und das Erstellen einer speziellen Struktur oder Klasse für die Rückgabewerte übertrieben wäre. Zum Beispiel

%Vor%

Dies ist ein ziemlich grundlegendes Muster in Sprachen, die Zeiger uneingeschränkt verwenden. In c / c ++ sieht man häufig Grundelemente, die nach Wert mit Klassen und Arrays als Zeiger übergeben werden. C # macht genau das Gegenteil, also ist 'ref' in Situationen wie dem obigen nützlich.

Wenn Sie eine Variable, die Sie aktualisieren möchten, in eine Funktion mit ref übergeben, ist nur eine Schreiboperation erforderlich, um Ihnen Ihr Ergebnis zu geben. Wenn Sie jedoch Werte zurückliefern, schreiben Sie normalerweise in eine Variable innerhalb der Funktion, geben sie zurück und schreiben sie dann erneut in die Zielvariable. Abhängig von den Daten könnte dies unnötigen Overhead verursachen. Jedenfalls sind dies die wichtigsten Dinge, die ich in der Regel vor der Verwendung des Ref-Keywords in Betracht ziehen.

Manchmal ist ref etwas schneller, wenn es in c # verwendet wird, aber nicht genug, um es als Rechtfertigung für die Leistung zu verwenden.

Hier ist, was ich auf einer 7 Jahre alten Maschine mit dem folgenden Code bekommen habe, indem ich eine 100k-Zeichenkette mit ref und nach Wert übergeben und aktualisieren ließ.

Ausgabe:

Iterationen: 10000000 Byref: 165ms byval: 417ms

%Vor%     
drankin2112 26.11.2013 05:20
quelle
3

Erstens: nicht , ob ref langsamer oder schneller ist. Es ist eine vorzeitige Optimierung. In 99,9999% -Fällen werden Sie nicht in eine Situation geraten, die zu einem Performance-Engpass führt.

Zweitens ist die Rückgabe des Ergebnisses der Berechnung als Rückgabewert im Gegensatz zur Verwendung von ref aufgrund der üblichen "funktionalen" Natur von C-ähnlichen Sprachen vorzuziehen. Es führt zu einer besseren Verkettung von Anweisungen / Aufrufen.

    
Ondrej Tucny 13.11.2011 10:46
quelle
2

Ich muss Ondrej hier zustimmen. Wenn du beginnst, alles mit ref zu übergeben, wirst du schließlich mit Entwicklern arbeiten, die dich für das Entwerfen einer solchen API erwürgen wollen!

Geben Sie einfach Zeug aus der Methode zurück, haben Sie nicht 100% Ihrer Methoden void zurückgeben. Was du machst, führt zu sehr unreinem Code und könnte andere Entwickler verwirren, die am Code arbeiten. Hier sollte die Übersichtlichkeit über die Leistung verbessert werden, da Sie sowieso nicht viel von der Optimierung profitieren.

Überprüfen Sie diesen SO-Beitrag: C # 'ref' Keyword, Leistung

und dieser Artikel von Jon Skeet: Ссылка

    
Jason Evans 13.11.2011 10:51
quelle

Tags und Links