簡體   English   中英

F#同步訪問列表

[英]F# synchronized access to list

假設我有一個系統中的整數列表:

let mutable data: int list = [1; 2; 3; 4; 5]

由相對較少的生產者更新(通過添加元素)並被許多消費者消費。

注意:如果消費者收到稍微過時的數據,則可以。

什么是同步訪問此變量的正確方法?

A )安全的方法是將此變量包裝到代理中並通過序列化消息訪問它,我們甚至不需要mutable修飾符。 但是這種方法似乎是次優的,因為它會不必要地使所有讀訪問同步。

B )AFAIK引用賦值在.NET中是原子的,因此在一個發布者和所有消費者之間進行簡單的賦值就足夠了:

發布者: data <- newItem :: data

消費者: data |> process

那么發布商之間的簡單鎖定就足以結束這個工作流程了嗎?

let monitor = object()

發布者: lock monitor (fun () -> data <- newItem::data)

我的假設是對的嗎? 哪種方法更受歡迎,對於F#來說更為慣用? 有更好的選擇嗎?

您可以使用Interlocked.CompareExchange來處理發布而不顯式鎖定:

let mutable data = [1;2;3;4;5]

let newValue = 0

// To publish:
let mutable tmp = data;
while not(tmp.Equals(Interlocked.CompareExchange(&data, newValue::data, tmp))) do
    tmp <- data

如果您有同步的編寫器,這可能會提供一個小的好處。

如果您確定希望消費者始終擁有最新數據,則ReaderWriterLockSlim將允許您完全同步數據,而不會強制每次調用時阻止讀取。

這可能看起來像:

let mutable data = [1;2;3;4;5]
let rwl = ReaderWriterLockSlim()

let newValue = 0

// To publish:
let publish newValue =
    rwl.EnterWriteLock()
    try
        data <- newValue :: data
    finally
        rwl.ExitWriteLock()

// To read:
let readCurrent =
    rwl.EnterReadLock()
    try
        data
    finally
        rwl.ExitReadLock()

如果您的共享數據是不可變的,您可以安全地執行此操作:

let monitor = new System.Object()
let data : int list ref = ref List.empty

let modData (modFun : int list -> int list) =
   lock (monitor) (fun _ -> data := modFun !data)

您可以隨時閱讀數據而無需鎖定。 數據是不可變的,因此它不能“在狀態之間”。 如果你需要原子地讀寫,你可以在“modFun”中完成。

用法示例:

modData (function |(head::tail) -> tail |_ -> List.Empty) //Remove one 
modData (fun thelist -> 1::thelist) //Add number 1 to head

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM