[英]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.