首頁 > 後端開發 > Golang > 主體

了解指標操作和 CPU/記憶體使用情況

王林
發布: 2024-02-08 22:20:32
轉載
662 人瀏覽過

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

php小編香蕉為您介紹指標操作和CPU/記憶體使用情況。在程式設計中,指標操作是一種強大的工具,可以直接存取和修改記憶體中的資料。透過了解指標操作,您可以更好地控制和優化程式碼的效能。另外,了解CPU和記憶體的使用情況對於最佳化程式也非常重要。透過監控和分析CPU和記憶體的使用情況,您可以找出潛在的效能問題,並採取相應的措施來提升程式的運作效率。在本文中,我們將為您詳細介紹指標操作和CPU/記憶體使用情況的相關知識,幫助您更好地理解和應用它們。

問題內容

我在工作中與一位同事討論將指標傳遞給函數和/或傳回指標是否更有效。

我整理了一些基準函數來測試執行此操作的不同方法。這些函數基本上接受一個變量,對其進行轉換並將其傳回。我們有 4 種不同的方法:

  1. 正常傳入變量,為轉換結果建立新變數並傳回它的副本
  2. 正常傳入變量,為轉換結果建立一個新變量,並傳回記憶體位址
  3. 傳入一個指向變數的指針,為轉換結果建立一個新變數並傳回該變數的副本
  4. 傳入一個指向變數的指針,將指針的值轉換,無需傳回任何內容。
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
}
登入後複製

我發現結果相當令人驚訝。

$ 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
登入後複製

在運行這個之前,我認為最有效的方法是第四個測試,因為在被調用的函數範圍內沒有創建新變量,並且只傳遞內存地址,但是,似乎第四個是效率最低的,花費最多的時間,並且使用最多的記憶體。

有人可以向我解釋這一點,或者為我提供一些很好的閱讀連結來解釋這一點嗎?

解決方法

您所做的基準測試並不能回答您提出的問題。事實證明,微基準測試極其困難——不僅在 go 世界中,而且在一般情況下也是如此。

回到效率問題。通常,將指標傳遞給函數不會轉義到堆。通常,從函數傳回的指標確實會逃逸到堆中。通常是這裡的關鍵字。您無法真正說出編譯器何時在堆疊上以及何時在堆疊上分配某些內容。這不是一個小問題。可以在此處找到非常好的簡短解釋。

但是如果您需要知道,可以詢問。您可以從簡單地列印編譯器所做的最佳化決策開始。您可以透過將 m 標誌傳遞給 go 工具compile 來完成此操作。

go build -gcflags -m=1
登入後複製

如果傳遞大於 1 的整數,則會得到更詳細的輸出。如果它沒有給您優化程式所需的答案,請嘗試分析。它遠遠超出了記憶體分析的範圍。

一般來說,在日常工作中不要為幼稚的最佳化決策而煩惱。不要太執著於「通常......」的說法,因為在現實世界中,你永遠不知道。始終先以正確性優化為目標。然後僅在您確實需要並證明您需要它時才進行效能最佳化。不要猜測,不要相信。另外,請記住,go 正在發生變化,因此我們在一個版本中證明的內容不一定在另一個版本中也成立。

以上是了解指標操作和 CPU/記憶體使用情況的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:stackoverflow.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!