繁体   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