1,數據庫I/O操作(異步)
數據庫本身是存儲在磁盤上。訪問和修改數據庫,即對磁盤進行讀寫,即I/O操作。
磁盤屬於計算機硬件,具有DMA能力,不需要CPU干預,可以實現異步操作。
I/O操作一般是消耗時間,sqlite使用異步處理I/O操作。
當有多個事務對數據庫進行操作,對應,也會有多個I/O操作。
操作系統將I/O操作,合理放入一個I/O隊列。一次性將隊列內的I/O操作提交給磁盤系統,並行處理多個I/O,提高效率。詳細請看鏈接,本人也沒有特別深入研究。
2,異步和多線程
異步和多線程,都有能力實現,不阻塞當前線程,使應用更“流暢”。 IOS最常見的, 不阻塞主線程,使UI表現更流暢。
兩者有區別。 具體請看鏈接。
總之,異步的實現,是基於計算機硬件的支持,而多線程,是操作系統中,一段邏輯代碼控制的。
3,線程安全以及處理
當一段代碼或者某個變量,被多個線程同時訪問和使用。 這些代碼或者變量,可能會出現非預期的效果,比如數據紊亂和數據安全的問題,這是“非安全的”。
為了線程安全, 需要在同一時刻,只能有一個線程訪問這些代碼或者變量,IOS中使用“互斥鎖”,來避免這個情況。
(互斥,mutex,從本身詞語意思:不相容,互相排斥的。數學上,A和B互斥, 指A和B沒有任何交集。 A和B不能同時發生。)
“互斥鎖”即@synchronized(對象A) {} ,對象A,只能被一個線程訪問。
因此,如果使用“互斥鎖”,一定是在, 多個線程,同時訪問一份資源的情況。
互斥鎖,增加了CPU的開銷。IOS中,atomic,就是為 setter 方法增加“互斥鎖”。比不要的情況下,一定要使用“nonatomic”。
4,sqlite3以及sqlite3的多線程
sqlite3是輕量級的數據庫。sqlite3同樣使用異步I/O操作,來讀取數據。關於sqlite3異步I/O操作,具體請看鏈接。
IOS中的sqlite3是線程安全的。IOS中UI在主線程,不阻塞UI線程,保證流暢,所以把sqlite的操作,需要遷移到子線程。這是sqlite3使用多線程的主要驅動力。
有一篇很好的文章,具體點擊鏈接。
- (1),單線程:禁用所有的mutex鎖,並發使用時會出錯。當SQLite編譯時加了SQLITE_THREADSAFE=0參數,或者在初始化SQLite前調用sqlite3_config(SQLITE_CONFIG_SINGLETHREAD)時啟用。
- (2),多線程:只要一個數據庫連接不被多個線程同時使用就是安全的。源碼中是啟用bCoreMutex,禁用bFullMutex。實際上就是禁用數據庫連接和prepared statement(准備好的語句)上的鎖,因此不能在多個線程中並發使用同一個數據庫連接或prepared statement。當SQLite編譯時加了SQLITE_THREADSAFE=2參數時默認啟用。若SQLITE_THREADSAFE不為0,可以在初始化SQLite前,調用sqlite3_config(SQLITE_CONFIG_MULTITHREAD)啟用;或者在創建數據庫連接時,設置SQLITE_OPEN_NOMUTEX flag。
- (3),串行:啟用所有的鎖,包括bCoreMutex和bFullMutex。因為數據庫連接和prepared statement都已加鎖,所以多線程使用這些對象時沒法並發,也就變成串行了。當SQLite編譯時加了SQLITE_THREADSAFE=1參數時默認啟用。若SQLITE_THREADSAFE不為0,可以在初始化SQLite前,調用sqlite3_config(SQLITE_CONFIG_SERIALIZED)啟用;或者在創建數據庫連接時,設置SQLITE_OPEN_FULLMUTEX flag。
IOS中的sqlite,默認使用(2)的配置。不方便的是,如果要被另外的線程訪問sqlite,其他的就必須關閉數據庫連接。 代碼中就有很多不方便的地方。
配置(1)不考慮,為單線程。
配置(3),將多線程變串行方式執行,
(暫停。。)