<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] ## 概述 公司`golang`項目需要優化,目的是減少`gpu`內存的使用。同一個模型被重復加載多次,使用更多的gpu內存,也增加 sync.Mutex的使用。 優化的方向是: * 減少代碼量的改動 * 減少gpu內存的使用,同一個模型只用加載一次 涉及的問題: * sync.Mutex是傳值還是傳引用? * sync.Mutex可以拷貝么? * sync.Mutex需要申明為指針么? ## sync.Mutex是傳值還是傳引用? 查看一個例子 ``` //test.go package main import ( "fmt" "sync" ) func sumMutexLock1(s sync.Mutex) { s.Lock() fmt.Printf("sumMutexLock1, s: %p\n", &s) defer s.Unlock() } func sumMutexLock2(s sync.Mutex) { s.Lock() fmt.Printf("sumMutexLock2, s: %p\n", &s) defer s.Unlock() } func main() { mutex := sync.Mutex{} fmt.Printf("TestMutex21, s: %p\n", &mutex) sumMutexLock1(mutex) sumMutexLock2(mutex) fmt.Println("TestMutex1") } ``` 運行程序后運行程序后輸出 ``` TestMutex21, s: 0xc00001e0c8 sumMutexLock1, s: 0xc00001e100 sumMutexLock2, s: 0xc00001e108 ``` 說明`mutex`的值被拷貝了一份。我猜想,如果在調用函數 `sumMutexLock1`之前上鎖 `mutex.Lock()`,則整個程序會進入死鎖狀態。代碼加上,驗證一下自己的想法,運行程序。沒想到golang這么簡單粗暴,程序直接panic。所以**sync.Mutex是傳值**。 ## copy 結構體操作可能導致非預期的死鎖 copy 結構體時,如果結構體中有鎖的話,記得重新初始化一個鎖對象,否則會出現非預期的死鎖: ``` // test.go package main import ( "fmt" "sync" ) type User struct { sync.Mutex name string } func main() { u1 := &User{name: "test"} u1.Lock() defer u1.Unlock() tmp := *u1 u2 := &tmp // u2.Mutex = sync.Mutex{} // 沒有這一行就會死鎖 fmt.Printf("%#p\n", u1) fmt.Printf("%#p\n", u2) u2.Lock() defer u2.Unlock() } ``` 運行 ``` $ go run test.go c00000c060 c00000c080 fatal error: all goroutines are asleep - deadlock! ``` ### 使用 go vet 工具檢查代碼中鎖的使用問題 可以通過[vet](https://golang.org/cmd/vet/)這個命令行來檢查上面的鎖 copy 的問題。比如上面的例子的檢查結果如下:: ``` $ go vet test.go # command-line-arguments ./test.go:17:9: assignment copies lock value to tmp: command-line-arguments.User ``` 可以看到 vet 提示 17 行那里的 copy 操作中 copy 了一個鎖。 ### 實際上 `sync.Mutex` 是繼承`nocopy`的 對于一個**互斥鎖**,實現是一個int值 和一個uint值構成的結構體。兩個值標識了鎖的狀態。 如果鎖可以copy,那鎖狀態也將被copy(由于struct 是值拷貝的),當鎖狀態再次更新后,copy后的值將不再有效。 因此,對于實現了`sync.Locker`接口的類型來說,理論上其實例是不能再次被賦值的。 ### golang noCopy 的實現 由于golang 中struct對象賦值是值拷貝, golang sync 包中 -`sync.Cond` -`sync.Pool` -`sync.WaitGroup` -`sync.Mutex` -`sync.RWMutex` -`...` 禁止拷貝,實現方式采用noCopy 的方式。 ``` package main import "fmt" type noCopy struct{} // Lock is a no-op used by -copylocks checker from `go vet`. func (*noCopy) Lock() {} func (*noCopy) Unlock() {} type S struct { noCopy data int } func main() { var s S ss := s fmt.Println(ss) } ``` golang 沒有禁止對實現`sync.Locker`接口的對象實例賦值進行報錯,只是在使用go vet 做靜態語法分析時,會提示錯誤。 ``` # command-line-arguments ./nocopy.go:19: assignment copies lock value to ss: main.S ./nocopy.go:20: call of fmt.Println copies lock value: main.S ``` ## sync.Mutex需要申明為指針么? 如果使用 指針`*sync.Mutex`,拷貝指針是不是相當于持有了同一把鎖了呢。雖然指針的基本原理都知道,指針存儲的是指向對象的地址,拷貝指針也就是拷貝指向對象的地址,但我還是寫代碼驗證一下: ``` package main import ( "fmt" "sync" "time" ) type Container struct { mutex *sync.Mutex wg sync.WaitGroup count int } func NewContainer() *Container { return &Container{ mutex: new(sync.Mutex), wg: sync.WaitGroup{}, count: 0, } } func (c *Container)start() { c.wg.Add(1000) for i := 0; i < 500; i++ { go c.sumMutexLock1(c.mutex) //把鎖以指針的形式傳進去 go c.sumMutexLock2(c.mutex) //把鎖以指針的形式傳進去 } c.wg.Wait() fmt.Printf("start, counts: %d\n\n", c.count) } func (c *Container)sumMutexLock1(s *sync.Mutex) { defer c.wg.Done() s.Lock() //使用拷貝進來的指針鎖加鎖 c.count++ fmt.Printf("sumMutexLock1, count: %d\n", c.count) s.Unlock() //使用拷貝進來的指針鎖解鎖 time.Sleep(time.Second*2) } func (c * Container)sumMutexLock2(s *sync.Mutex) { defer c.wg.Done() s.Lock() //使用拷貝進來的指針鎖加鎖 c.count++ c.mutex.Unlock() fmt.Printf("sumMutexLock2, counts: %d\n", c.count) time.Sleep(time.Second*1) } func main() { c := NewContainer() c.start() } ``` 看到最后結果輸出的是: ``` start, counts: 1000 ``` **說明拷貝鎖的指針,相當于持有了同一把鎖。** ## 總結 * `sync.Mutex`是傳值,如果`copy結構體`可能能會導致死鎖,`sync.Mutex`是`noCopy`的。; * 我認為可以將`* sync.Mutex`視為簡單指針。如果你想要使用它,您應該聲明并初始化它,但是如果使用`sync.Mutex`,它已經被初始化。 * 我認為需要聲明為指針 `*sync.Mutex`,它們總是傳遞要使用的可變指針,因為傳遞`struct`會復制,但是如果使用指針,您需要傳遞的只是一個指針。 (我的意思是,不需要花費副本)。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看