Heim  >  Artikel  >  Backend-Entwicklung  >  Zeigeroperationen und CPU-/Speichernutzung verstehen

Zeigeroperationen und CPU-/Speichernutzung verstehen

王林
王林nach vorne
2024-02-08 22:20:32664Durchsuche

了解指针操作和 CPU/内存使用情况

Der PHP-Editor Banana führt Sie in Zeigeroperationen und CPU-/Speichernutzung ein. In der Programmierung ist die Zeigermanipulation ein leistungsstarkes Werkzeug, das direkt auf Daten im Speicher zugreifen und diese ändern kann. Durch das Verständnis von Zeigeroperationen können Sie die Leistung Ihres Codes besser steuern und optimieren. Darüber hinaus ist es für die Optimierung von Programmen sehr wichtig, die CPU- und Speichernutzung zu verstehen. Durch die Überwachung und Analyse der CPU- und Speichernutzung können Sie potenzielle Leistungsprobleme erkennen und geeignete Maßnahmen ergreifen, um die Effizienz des Programmbetriebs zu verbessern. In diesem Artikel stellen wir Ihnen die relevanten Kenntnisse zu Zeigeroperationen und CPU-/Speichernutzung im Detail vor, damit Sie diese besser verstehen und anwenden können.

Inhalt der Frage

Ich habe mit einem Arbeitskollegen darüber diskutiert, ob es effizienter wäre, einen Zeiger auf eine Funktion zu übergeben und/oder einen Zeiger zurückzugeben.

Ich habe einige Benchmark-Funktionen zusammengestellt, um verschiedene Vorgehensweisen zu testen. Diese Funktionen nehmen grundsätzlich eine Variable, konvertieren sie und geben sie zurück. Wir haben 4 verschiedene Methoden:

  1. Übergeben Sie die Variable wie gewohnt, erstellen Sie eine neue Variable für das Konvertierungsergebnis und geben Sie eine Kopie davon zurück
  2. Übergeben Sie die Variable normal, erstellen Sie eine neue Variable für das Konvertierungsergebnis und geben Sie die Speicheradresse zurück
  3. Übergeben Sie einen Zeiger auf eine Variable, erstellen Sie eine neue Variable für das Konvertierungsergebnis und geben Sie eine Kopie der Variablen zurück
  4. Übergeben Sie einen Zeiger auf eine Variable und konvertieren Sie den Wert des Zeigers, ohne etwas zurückzugeben.
package main

import (
    "fmt"
    "testing"
)

type mystruct struct {
    mystring string
}

func acceptparamreturnvariable(s mystruct) mystruct {
    ns := mystruct{
        fmt.sprintf("i'm quoting this: \"%s\"", s.mystring),
    }
    return ns
}

func acceptparamreturnpointer(s mystruct) *mystruct {
    ns := mystruct{
        fmt.sprintf("i'm quoting this: \"%s\"", s.mystring),
    }
    return &ns
}

func acceptpointerparamreturnvariable(s *mystruct) mystruct {
    ns := mystruct{
        fmt.sprintf("i'm quoting this: \"%s\"", s.mystring),
    }
    return ns
}

func acceptpointerparamnoreturn(s *mystruct) {
    s.mystring = fmt.sprintf("i'm quoting this: \"%s\"", s.mystring)
}

func benchmarknormalparamreturnvariable(b *testing.b) {
    s := mystruct{
        mystring: "hello world",
    }
    var ns mystruct
    for i := 0; i < b.n; i++ {
        ns = acceptparamreturnvariable(s)
    }
    _ = ns
}

func benchmarknormalparamreturnpointer(b *testing.b) {
    s := mystruct{
        mystring: "hello world",
    }
    var ns *mystruct
    for i := 0; i < b.n; i++ {
        ns = acceptparamreturnpointer(s)
    }
    _ = ns
}

func benchmarkpointerparamreturnvariable(b *testing.b) {
    s := mystruct{
        mystring: "hello world",
    }
    var ns mystruct
    for i := 0; i < b.n; i++ {
        ns = acceptpointerparamreturnvariable(&s)
    }
    _ = ns
}

func benchmarkpointerparamnoreturn(b *testing.b) {
    s := mystruct{
        mystring: "hello world",
    }
    for i := 0; i < b.n; i++ {
        acceptpointerparamnoreturn(&s)
    }
    _ = s
}

Ich fand die Ergebnisse ziemlich überraschend.

$ go test -run=XXXX -bench=. -benchmem
goos: darwin
goarch: amd64
pkg: XXXX
cpu: Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
BenchmarkNormalParamReturnVariable-16           10538138               103.3 ns/op            48 B/op          2 allocs/op
BenchmarkNormalParamReturnPointer-16             9526380               201.2 ns/op            64 B/op          3 allocs/op
BenchmarkPointerParamReturnVariable-16           7542066               147.0 ns/op            48 B/op          2 allocs/op
BenchmarkPointerParamNoReturn-16                   45897            119265 ns/op          924351 B/op          5 allocs/op

Bevor ich dies ausführte, dachte ich, dass der vierte Test der effizienteste Weg wäre, da im Rahmen der aufgerufenen Funktion keine neuen Variablen erstellt werden und nur die Speicheradresse übergeben wird. Allerdings scheint der vierte Test der geringste zu sein effizient, Nimmt die meiste Zeit in Anspruch und verbraucht den meisten Speicher.

Kann mir das jemand erklären oder mir ein paar gute Leselinks zur Verfügung stellen, die das erklären?

Problemumgehung

Der von Ihnen durchgeführte Benchmark beantwortet die von Ihnen gestellte Frage nicht. Es stellt sich heraus, dass Mikrobenchmarking äußerst schwierig ist – nicht nur in der mobilen Welt, sondern im Allgemeinen.

Zurück zum Thema Effizienz. Normalerweise erfolgt die Übergabe von Zeigern auf Funktionen nicht an den Heap. Normalerweise entkommen von Funktionen zurückgegebene Zeiger auf den Heap. Normalerweise ist hier das Schlüsselwort. Man kann nicht wirklich sagen, wann der Compiler etwas auf dem Stapel und wann er etwas auf dem Heap zuweist. Das ist kein kleines Problem. Eine sehr gute kurze Erklärung gibt es hier.

Aber wenn Sie es wissen müssen, können Sie fragen. Sie können damit beginnen, einfach die vom Compiler getroffenen Optimierungsentscheidungen auszudrucken. Sie können dies tun, indem Sie m 标志传递给 go 工具compile hinzufügen.

go build -gcflags -m=1

Wenn Sie eine Ganzzahl größer als 1 übergeben, erhalten Sie eine ausführlichere Ausgabe. Wenn Sie damit nicht die Antworten erhalten, die Sie zur Optimierung Ihres Programms benötigen, versuchen Sie es mit Analyse. Es geht weit über die Gedächtnisanalyse hinaus.

Generell sollten Sie sich in Ihrer täglichen Arbeit nicht mit naiven Optimierungsentscheidungen herumschlagen. Hängen Sie sich nicht zu sehr auf „normalerweise …“ ein, denn in der realen Welt weiß man nie. Streben Sie immer zuerst eine Korrektheitsoptimierung an. Dann optimieren Sie die Leistung nur dann, wenn Sie sie wirklich brauchen, und beweisen Sie, dass Sie sie brauchen. Raten Sie nicht, glauben Sie nicht. Bedenken Sie außerdem, dass sich go ändert, sodass das, was wir in einer Version beweisen, nicht unbedingt auch in einer anderen zutrifft.

Das obige ist der detaillierte Inhalt vonZeigeroperationen und CPU-/Speichernutzung verstehen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen