<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>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                > 原子操作即是進行過程中不能被中斷的操作。針對某個值的原子操作在被進行的過程中,CPU絕不會再去進行其他的針對該值的操作。 為了實現這樣的嚴謹性,原子操作僅會由一個獨立的CPU指令代表和完成。 - GO語言提供的原子操作都是非入侵式的,由標準庫sync/atomic中的眾多函數代表 - 類型包括int32,int64,uint32,uint64,uintptr,unsafe.Pointer,共六個。 - 這些函數提供的原子操作共有五種:增或減,比較并交換,載入,存儲和交換 # int各種類型取值范圍 | 類型 | 長度(字節) | 值范圍 | |-----|-----|-----| | int8 | 1 | -128 ~ 127 | | uint8(byte) | 1 | 0 ~ 255 | | int16 | 2 | 32768~32767 | | uint16 | 2 | 0~65535 | | int32 | 4 | 2147483648~2147483647 | | uint32 | 4 | 0~4294967295 | | int64 | 8 | -9223372036854775808~9223372036854775807 | | uint64 | 8 | 0~18446744073709551615 | | int | 平臺相關 | 平臺相關 | | uint | 平臺相關 | 平臺相關 | | uintptr | 同指針 | 在32位平 下為4字節,64位平 下為8字節 | # 增或減Add 函數名稱都以Add為前綴,并后跟針對的具體類型的名稱。 - 被操作的類型只能是數值類型 - int32,int64,uint32,uint64,uintptr類型可以使用原子增或減操作 - 第一個參數值必須是一個指針類型的值,以便施加特殊的CPU指令 - 第二個參數值的類型和第一個被操作值的類型總是相同的。 ### 示例 ~~~ package main import ( "fmt" "sync/atomic" ) func main(){ var i32 int32 fmt.Println("=====old i32 value=====") fmt.Println(i32) //第一個參數值必須是一個指針類型的值,因為該函數需要獲得被操作值在內存中的存放位置,以便施加特殊的CPU指令 //結束時會返回原子操作后的新值 newI32 := atomic.AddInt32(&i32,3) fmt.Println("=====new i32 value=====") fmt.Println(i32) fmt.Println(newI32) var i64 int64 fmt.Println("=====old i64 value=====") fmt.Println(i64) newI64 := atomic.AddInt64(&i64,-3) fmt.Println("=====new i64 value=====") fmt.Println(i64) fmt.Println(newI64) } ~~~ 結果: /usr/local/go/bin/go run /Users/liuxinming/go/src/free/learngo/atomic/add/add.go =====old i32 value===== 0 =====new i32 value===== -3 -3 =====old i64 value===== 0 =====new i64 value===== -3 -3 # 比較并交換CAS Compare And Swap 簡稱CAS,在sync/atomic包種,這類原子操作由名稱以‘CompareAndSwap’為前綴的若干個函數代表。 - 聲明如下 ~~~ func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool) ~~~ - 調用函數后,會先判斷參數addr指向的被操作值與參數old的值是否相等 - 僅當此判斷得到肯定的結果之后,才會用參數new代表的新值替換掉原先的舊值,否則操作就會被忽略。 - so, 需要用for循環不斷進行嘗試,直到成功為止 - 使用鎖的做法趨于悲觀 - 我們總假設會有并發的操作要修改被操作的值,并使用鎖將相關操作放入臨界區中加以保護 - 使用CAS操作的做法趨于樂觀 - 總是假設被操作值未曾被改變(即與舊值相等),并一旦確認這個假設的真實性就立即進行值替換。 ### 示例 ~~~ package main import ( "fmt" "sync/atomic" ) var value int32 func main() { fmt.Println("======old value=======") fmt.Println(value) fmt.Println("======CAS value=======") addValue(3) fmt.Println(value) } //不斷地嘗試原子地更新value的值,直到操作成功為止 func addValue(delta int32){ //在被操作值被頻繁變更的情況下,CAS操作并不那么容易成功 //so 不得不利用for循環以進行多次嘗試 for { v := value if atomic.CompareAndSwapInt32(&value, v, (v + delta)){ //在函數的結果值為true時,退出循環 break } //操作失敗的緣由總會是value的舊值已不與v的值相等了. //CAS操作雖然不會讓某個Goroutine阻塞在某條語句上,但是仍可能會使流產的執行暫時停一下,不過時間大都極其短暫. } } ~~~ 結果: ======old value======= 0 ======CAS value======= 3 # 載入Load 上面的比較并交換案例總 v:= value為變量v賦值,但… 要注意,在進行讀取value的操作的過程中,其他對此值的讀寫操作是可以被同時進行的,那么這個讀操作很可能會讀取到一個只被修改了一半的數據. - so so so , 我們要使用sync/atomic代碼包同樣為我們提供了一系列的函數,以Load為前綴(載入),來確保這樣的糟糕事情發生。 ### 示例 ~~~ package main import ( "fmt" "sync/atomic" ) var value int32 func main() { fmt.Println("======old value=======") fmt.Println(value) fmt.Println("======CAS value=======") addValue(3) fmt.Println(value) } //不斷地嘗試原子地更新value的值,直到操作成功為止 func addValue(delta int32){ //在被操作值被頻繁變更的情況下,CAS操作并不那么容易成功 //so 不得不利用for循環以進行多次嘗試 for { //v := value //在進行讀取value的操作的過程中,其他對此值的讀寫操作是可以被同時進行的,那么這個讀操作很可能會讀取到一個只被修改了一半的數據. //因此我們要使用載入 v := atomic.LoadInt32(&value) if atomic.CompareAndSwapInt32(&value, v, (v + delta)){ //在函數的結果值為true時,退出循環 break } //操作失敗的緣由總會是value的舊值已不與v的值相等了. //CAS操作雖然不會讓某個Goroutine阻塞在某條語句上,但是仍可能會使流產的執行暫時停一下,不過時間大都極其短暫. } } ~~~ - atomic.LoadInt32接受一個*int32類型的指針值 - 返回該指針指向的那個值 # 存儲Store > 與讀取操作相對應的是寫入操作。 而sync/atomic包也提供了與原子的載入函數相對應的原子的值存儲函數。 以Store為前綴 - 在原子地存儲某個值的過程中,任何CPU都不會進行針對同一個值的讀或寫操作。 - 原子的值存儲操作總會成功,因為它并不會關心被操作值的舊值是什么 - 和CAS操作有著明顯的區別 ~~~ fmt.Println("======Store value=======") atomic.StoreInt32(&value, 10) fmt.Println(value) ~~~ # 交換Swap - 與CAS操作不同,原子交換操作不會關心被操作的舊值。 - 它會直接設置新值 - 它會返回被操作值的舊值 - 此類操作比CAS操作的約束更少,同時又比原子載入操作的功能更強 # 實際案例(繼續改造上一版代碼) ~~~ //數據文件的實現類型 type myDataFile struct { f *os.File //文件 fmutex sync.RWMutex //被用于文件的讀寫鎖 rcond *sync.Cond //讀操作需要用到的條件變量 woffset int64 // 寫操作需要用到的偏移量 roffset int64 // 讀操作需要用到的偏移量 dataLen uint32 //數據塊長度 } //此處省略... func (df *myDataFile) Read() (rsn int64, d Data, err error){ // 讀取并更新讀偏移量 var offset int64 for { offset = atomic.LoadInt64(&df.roffset) if atomic.CompareAndSwapInt64(&df.roffset, offset, (offset + int64(df.dataLen))){ break } } //讀取一個數據塊,最后讀取的數據塊序列號 rsn = offset / int64(df.dataLen) bytes := make([]byte, df.dataLen) //讀寫鎖:讀鎖定 df.fmutex.RLock() defer df.fmutex.RUnlock() for { _, err = df.f.ReadAt(bytes, offset) if err != nil { if err == io.EOF { //暫時放棄fmutex的 讀鎖,并等待通知的到來 df.rcond.Wait() continue } } break } d = bytes return } func (df *myDataFile) Write(d Data) (wsn int64, err error){ //讀取并更新寫的偏移量 var offset int64 for { offset = atomic.LoadInt64(&df.woffset) if atomic.CompareAndSwapInt64(&df.woffset, offset, (offset + int64(df.dataLen))){ break } } //寫入一個數據塊,最后寫入數據塊的序號 wsn = offset / int64(df.dataLen) var bytes []byte if len(d) > int(df.dataLen){ bytes = d[0:df.dataLen] }else{ bytes = d } df.fmutex.Lock() defer df.fmutex.Unlock() _, err = df.f.Write(bytes) //發送通知 df.rcond.Signal() return } func (df *myDataFile) Rsn() int64{ offset := atomic.LoadInt64(&df.roffset) return offset / int64(df.dataLen) } func (df *myDataFile) Wsn() int64{ offset := atomic.LoadInt64(&df.woffset) return offset / int64(df.dataLen) } ~~~ 完整代碼放在GITHUB: [https://github.com/lxmgo/learngo](https://github.com/lxmgo/learngo) 一些學習過程整理,希望對大家學習Go語言有所幫助。
                  <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>

                              哎呀哎呀视频在线观看