F#同步访问列表

Gro*_*ozz 5 f# multithreading immutability agent

假设我有一个系统中的整数列表:

let mutable data: int list = [1; 2; 3; 4; 5]
Run Code Online (Sandbox Code Playgroud)

由相对较少的生产者更新(通过添加元素)并被许多消费者消费.

注意:如果消费者收到稍微过时的数据,则可以.

什么是同步访问此变量的正确方法?

A)安全的方法是将此变量包装到代理中并通过序列化消息访问它,我们甚至不需要mutable修饰符.但是这种方法似乎是次优的,因为它会不必要地使所有读访问同步.

B)AFAIK引用赋值在.NET中是原子的,因此在一个发布者和所有消费者之间进行简单的赋值就足够了:

出版商: data <- newItem :: data

消费者: data |> process

那么发布商之间的简单锁定就足以结束这个工作流程了吗?

let monitor = object()
Run Code Online (Sandbox Code Playgroud)

出版商: lock monitor (fun () -> data <- newItem::data)

我的假设是对的吗?哪种方法更受欢迎,对于F#来说更为惯用?有更好的选择吗?

Ree*_*sey 8

您可以使用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
Run Code Online (Sandbox Code Playgroud)

如果您有同步的编写器,这可能会提供一个小的好处.

如果您确定希望消费者始终拥有最新数据,则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()
Run Code Online (Sandbox Code Playgroud)