2017-08-14 3 views
-4

Wenn meine Tests nicht falsch sind, benötigen alle anderen Optionen, einschließlich der Verwendung von einfachen Funktionen, etwa 35% länger als Methoden in einem anderen Paket mit einem eingebetteten Alias ​​definiert. Ich habe wahrscheinlich etwas falsch gemacht, und ich würde gerne wissen, was es ist. Für vollständige Details siehe this repository.Verwendet einen eingebetteten Alias, um Methoden auf einer Struktur in einem anderen Paket effizient zu definieren?

[EDIT] Danke für die Kommentare/Vorschläge. Das Folgende zeigt nur Code, der sich auf den Vergleich von "Methode" zu "Meth" bezieht. Ersteres verwendet typische Methoden, die im models-Paket zusammen mit dem struct definiert sind. Die Option "meth" definiert Methoden, die einen eingebetteten Alias ​​verwenden, der im Paket datactrl definiert ist. Das erste Codebeispiel enthält die Strukturdefinition und eine exportierte Standardinstanz der in den Tests verwendeten Struktur.

von Paket-Modelle, Datei models.go

type CmntData struct { 
    ID   int 
    Slug  string 
    Title  string 
    PageID  int 
    Text  string 
    DateCreated time.Time 
    CreatedBy int 
} 

var DefaultCD = CmntData{ID: 100, Title: "Demo Comment", 
Text: "This is a test comment", PageID: 1000, CreatedBy: 4242} 


// Local methods called by the "method" test 

func (cd *CmntData) NewComment(ncd CmntData) *CmntData { 

    ncd.DateCreated = time.Now() 

    return &ncd 
} 

func (cd *CmntData) DefaultComment(cnt int) *CmntData { 

    dcd := DefaultCD 
    dcd.Slug = "demo-comment-" + strconv.Itoa(cnt + 1) 

    return cd.NewComment(dcd) 
} 

von Paket datactrl, Datei comments.go

// Types and method definitions used to add methods to models.CmntData 

type roCmntData struct { 
    ModelCD models.CmntData 
} 

type roCD struct{} 

// roComment allows us to effectively add methods to models.CmntData. 
// Data and "local" methods defined for models.CmntData are accessible. 
type roComment struct { 
    *roCmntData // Provides access to models.CmntData 
    *roCD  // Required to make the magic happen 
} 

// Other packages must use Rcd to access methods added to models.CmntData 
var Rcd = roComment { 
    roCmntData: &roCmntData{}, 
    roCD: &roCD{}, 
} 

// Remote methods called by the "meth" test 

func (cd *roComment) NewComment(ncd models.CmntData) *models.CmntData { 

    cd.roCmntData.ModelCD = ncd 
    cd.ModelCD.DateCreated = time.Now() 

    return &cd.ModelCD 
} 

func (cd *roComment) DefaultComment(cnt int) *models.CmntData { 

    dcd := models.DefaultCD 
    dcd.Slug = "demo-comment-" + strconv.Itoa(cnt + 1) 

    return cd.NewComment(dcd) 
} 

von Paket Haupt, file main.go

if cmd == "method" { 
    tstart := time.Now() 
    dcd := models.CmntData{} 
    for i := 0; i < limit; i++ { 
     defCD = dcd.DefaultComment(i) 
    } 
    tfinish := time.Now() 
    elapsed = tfinish.Sub(tstart) 
} 

if cmd == "meth" { 
    tstart := time.Now() 

    // datactrl.Rcd provides access to remote models.CmntData methods 
    dcd := &datactrl.Rcd 
    for i := 0; i < limit; i++ { 
     defCD = dcd.DefaultComment(i) 
    } 
    tfinish := time.Now() 
    elapsed = tfinish.Sub(tstart) 
} 

Screen shot of results Der Durchschnitt von 40 Schleifen, wobei jede Schleife den Durchschnitt von einer Million Testläufen zurückgibt. Für die Aufzeichnung, beide "func" und "Funktion" Tests abgeschlossen innerhalb von 2ms von dem Ergebnis von "Methode".

+0

Was soll man von Ihrem Code sehen? Alle 4 Dinge laufen ungefähr zur gleichen Zeit hier. – zerkms

+3

Können Sie den Code auf das Minimum konvertieren, um das Problem zu veranschaulichen und zu teilen, könnte ein https://play.golang.org würde tun –

+2

Haben Sie versucht, die Demontage zu betrachten? Außerdem: Ihre Methoden nehmen einen Zeigerempfänger, die Funktionen nehmen ein Wertargument. Der Methode wird ein Zeiger übergeben, den Funktionen wird das vollständige Objekt übergeben. Wenn der Compiler diesen Unterschied nicht optimiert (was ich nicht glaube), würde das den Unterschied in der Leistung erklären. –

Antwort

-1

Eigentlich @JimB beantwortet meine Frage, aber es ist in einem Kommentar zu der Frage.

Die Antwort scheint zu sein, dass typische Methoden, die im selben Paket wie die Struktur definiert sind, in der sie Teil werden, eine zusätzliche Speicherzuweisung erfordern. Was ich als remote Methodendefinitionen bezeichnet habe, bekommt als Ergebnis eine winzige Kante.

Denken Sie daran, dass die Kante möglicherweise nicht wert ist, etwas zu tun, das viele Kommentare erfordert, um zu klären, was vor sich geht. Auf der anderen Seite, wenn Sie Datenmanipulation von Datendefinition trennen wollen/wollen, können remote Methoden Ihnen dies ermöglichen, und Sie sparen, was bei jedem Aufruf ein paar Mikrosekunden beträgt, als zusätzlichen Bonus. :)

Sein Vorschlag, Go's Benchmark-Einrichtung zu verwenden, die mit Tests eingebaut ist, klingt wie ein guter. Ich werde es mir selbst ansehen.

+0

'Methoden, die im selben Paket definiert sind wie die Struktur, zu der sie gehören, erfordern eine zusätzliche Speicherzuweisung' - nein, das ist nicht der Grund für die zusätzliche Zuweisung. Der "Methoden" -Test erstellt jedes Mal einen neuen Wert, während der "Meth" -Test jedes Mal einen Wert an die gleiche Stelle schreibt, die zuvor in "Rcd" zugewiesen wurde. Sie können dies testen, indem Sie die Adresse des Rückgabezeigers in jedem Fall betrachten. – JimB

+0

Interessant. Bedeutet das, dass "Methode" theoretisch geändert werden könnte, um das Gleiche zu tun? In der Praxis besteht der Wert (für mich) von "meth" darin, Methoden für eine Struktur definieren zu können, die in einem anderen Paket definiert ist. Ich sehe jetzt, dass das Abschneiden der Zeit um 25% bedeutungslos ist, weil ein Methodenaufruf so schnell ist, damit anzufangen. Danke, dass Sie sich die Zeit genommen haben, sich die Sache genauer anzusehen. – emadera52

Verwandte Themen