1. 程式人生 > >[Erlang]Ets併發讀寫詳解

[Erlang]Ets併發讀寫詳解

ETS是Erlang內建的記憶體資料庫,可用於多程序共享資料,具有併發讀寫的效能,文章就這點展開探討,重點說說ets併發讀寫兩個引數的優缺點及適用場合。

 

比如新建一個person的ets表:

ets:new(person, [set, public, named_table, {write_concurrency, true}, {read_concurrency, true} ]).

 

說說ets併發讀寫的兩個引數:write_concurrency / read_concurrency

 

write_concurrency(併發寫)

可以提高多程序併發寫ets的效率。通常來說,ets寫資料時整張表是鎖定的,其他程序不能進行讀寫直到前面的操作完成。併發寫可以改變這個情況,同一個表中的不同物件可以被多個程序併發讀寫。有了這個引數,使得ets寫記錄時鎖表變成了鎖記錄,提高了併發讀寫效率。但併發寫也有弊端,降低資料連續寫入的效率和效能。如果有且只有一個程序在讀寫資料,將會帶來一定的開銷。而測試發現這個開銷比較小,可以忽略。而且,只有一個程序在讀寫資料的場合比較小。

所以,併發寫的適用場合如下:

 1. 資料併發讀寫很頻繁

 2. 併發讀寫的資料量比較少(取記錄數)

但是,像這樣一次性插入多條記錄,ets要保證原子性,併發效率會大打折扣:

ets:insert(person, [{john, 28}, {lucy, 25}, {tom, 2}]).

[cpp] view plaincopy

  1. /* ets:insert/2 的實現(erl_db.c) 
  2.  * 如果第2個引數是列表,就鎖表,不是就鎖記錄 
  3.  */  
  4.   
  5. /* Write lock table if more than one object to keep atomicy */  
  6.   kind = ((is_list(BIF_ARG_2) && CDR(list_val(BIF_ARG_2)) != NIL)  
  7.    ? LCK_WRITE : LCK_WRITE_REC);  

 

read_concurrency(併發讀)

優化ets併發讀效能,特別是在多核smp的支援下,讀操作變得比較廉價。但是同時也帶來一個問題,讀寫操作之間的切換消耗更多的效能。

所以,併發讀的適用場合如下:

 1. 讀比寫更加頻繁

 2. 大量的讀少量寫,大量的寫少量讀

 

什麼時候使用這兩個引數?

   1. 使用write_concurrency引數大多時候是有效的,測試寫操作效能提高3~4倍,而且,在單程序寫多程序讀的場合下也同樣適用。如果併發讀寫次數較少,而且每次都要讀取或者寫入大量資料就不適合了。

   2. read_concurrency的使用要看場合,並不是高併發就適合。如果每次讀的資料和寫的資料都很少,而且讀寫都很頻繁,就沒必要使用這個引數。如果很少寫資料,大多時候都是讀資料的話用這個引數就很適用了。另外,如果資料讀寫頻繁,但每次讀寫的資料都很多,也適當考慮用這個引數。