在學習Redis的常用操作時,經常看到介紹說,Redis的set、get以及hset等等指令的執行都是原子性的,但是令自己百思不得其解的是,為什麼這些操作是原子性的?
## 原子性
原子性是資料庫的事務中的特性。在資料庫事務的情景下,原子性指的是:一個事務(transaction)中的所有操作,要麼全部完成,要麼全部不完成,不會結束在中間某個環節。[【維基百科】](https://zh.wikipedia.org/wiki/ACID)
對于Redis而言,指令的原子性指的是:一個操作的不可以再分,操作要麼執行,要麼不執行。
原子性是資料庫的事務中的特性。在資料庫事務的情景下,原子性指的是:一個事務(transaction)中的所有操作,要麼全部完成,要麼全部不完成,不會結束在中間某個環節。【維基百科】
Redis的操作之是以是原子性的,是因為Redis是單線程的。
由于對作業系統相關的知識不是很熟悉,從上面這句話并不能真正了解Redis操作是原子性的原因,進一步查閱程序與線程的概念及其差別。
計算機中已執行程式的實體。【維基百科】。比如,一個啟動了的php-fpm,就是一個程序。
作業系統能夠進行運算排程的最小單元。它被包含在程序之中,是程序的實際運作機關。一條線程指的是程序中一個單一順序的控制流,一個程序中可以并發多個線程,每條線程并行執行不同的任務。【維基百科】。比如,mysql運作時,mysql啟動後,該mysql服務就是一個程序,而mysql的連接配接、查詢的操作,就是線程。
資源(如打開檔案):程序間的資源互相獨立,同一程序的各線程間共享資源。某程序的線程在其他程序不可見。 通信:程序間通信:消息傳遞、同步、共享記憶體、遠端過程調用、管道。線程間通信:直接讀寫程序資料段(需要程序同步和互斥手段的輔助,以保證資料的一緻性)。 排程和切換:線程上下文切換比程序上下文切換要快得多。
線程,是作業系統最小的執行單元,在單線程程式中,任務一個一個地做,必須做完一個任務後,才會去做另一個任務。
Redis的API是原子性的操作,那麼多個指令在并發中也是原子性的嗎?
看看下面這段代碼:
用兩個終端執行上面的程式,發現val的結果是小于2000的值,那麼可以知道,在程式中執行多個Redis指令并非是原子性的,這也和普通資料庫的表現是一樣的。
如果想在上面的程式中實作原子性,可以将get和set改成單指令操作,比如incr,或者使用Redis的事務,或者使用Redis+Lua的方式實作。
綜上所述,對Redis來說,執行get、set以及eval等API,都是一個一個的任務,這些任務都會由Redis的線程去負責執行,任務要麼執行成功,要麼執行失敗,這就是Redis的指令是原子性的原因。
Redis本身提供的所有API都是原子操作,Redis中的事務其實是要保證批量操作的原子性。
原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。
如果本文對你有幫助,請點下推薦吧,謝謝_