Concurrency MailboxProcessor类型是锁的替代品吗?

Concurrency MailboxProcessor类型是锁的替代品吗?,concurrency,f#,message-passing,Concurrency,F#,Message Passing,我一直在慢慢地研究F#带来的所有特性。特别引起我兴趣的是MailboxProcessor 在C#中,与此类似的代码最有可能使用锁。我们可以考虑邮件处理程序< /代码>作为锁的替换吗? 在下面的例子中,我在做什么 任何特别幼稚的事情都可以 你看到什么了吗 改善了吗 module Tcp = open System open System.Collections.Generic open System.Net open System.Net.Sockets

我一直在慢慢地研究F#带来的所有特性。特别引起我兴趣的是
MailboxProcessor

  • 在C#中,与此类似的代码最有可能使用锁。我们可以考虑<代码>邮件处理程序< /代码>作为锁的替换吗?
  • 在下面的例子中,我在做什么 任何特别幼稚的事情都可以 你看到什么了吗 改善了吗

  • module Tcp =
        open System
        open System.Collections.Generic
        open System.Net
        open System.Net.Sockets
        open System.Threading    
    
        type SocketAsyncMessage =
            | Get of AsyncReplyChannel<SocketAsyncEventArgs>
            | Put of SocketAsyncEventArgs
            | Dispose of AsyncReplyChannel<MailboxProcessor<SocketAsyncMessage>>
    
        type SocketAsyncEventArgsPool(size:int) =             
            let agent = 
                lazy(MailboxProcessor.Start(
                        (fun inbox ->
                            let references = lazy(new List<SocketAsyncEventArgs>(size))       
                            let idleReferences = lazy(new Queue<SocketAsyncEventArgs>(size))                    
                            let rec loop () = 
                                async {
                                    let! message = inbox.Receive()
                                    match message with
                                    | Get channel -> 
                                        if idleReferences.Value.Count > 0 then
                                            channel.Reply(idleReferences.Value.Dequeue())
                                        else    
                                            let args = new SocketAsyncEventArgs()
                                            references.Value.Add args
                                            channel.Reply args  
                                        return! loop()
                                    | Put args ->
                                        if args = null then
                                            nullArg "args" 
                                        elif references.Value.Count < size then
                                            idleReferences.Value.Enqueue args
                                        else                                       
                                            if not(references.Value.Remove args) then
                                                invalidOp "Reference not found."                                        
                                            args.Dispose() 
                                        return! loop()
                                    | Dispose channel ->
                                        if references.IsValueCreated then
                                            references.Value 
                                            |> Seq.iter(fun args -> args.Dispose())
                                        channel.Reply inbox 
                                }
                            loop())))
    
            /// Returns a SocketAsyncEventArgs instance from the pool.         
            member this.Get () =
                agent.Value.PostAndReply(fun channel -> Get channel)            
            /// Returns the SocketAsyncEventArgs instance to the pool. 
            member this.Put args =
                agent.Value.Post(Put args)
            /// Releases all resources used by the SocketAsyncEventArgsPool.
            member this.Dispose () =
                (this:>IDisposable).Dispose()  
    
            interface IDisposable with
                 member this.Dispose() =
                    if agent.IsValueCreated then
                        (agent.Value.PostAndReply(fun channel -> Dispose channel):>IDisposable).Dispose()
    
    模块Tcp=
    开放系统
    open System.Collections.Generic
    开放系统.Net
    开放式System.Net.Sockets
    开放系统。线程
    输入SocketAsyncMessage=
    |AsyncReplyChannel的获取
    |SocketAsyncEventArgs的放置
    |处置AsyncReplyChannel
    类型SocketAsyncEventArgsPool(大小:int)=
    让代理=
    惰性(MailboxProcessor.Start(
    (趣味收件箱->
    let references=lazy(新列表(大小))
    让idleReferences=lazy(新队列(大小))
    让rec循环()=
    异步的{
    let!message=inbox.Receive()
    将消息与匹配
    |获取频道->
    如果idleReferences.Value.Count>0,则
    channel.Reply(idleReferences.Value.Dequeue())
    其他的
    设args=new SocketAsyncEventArgs()
    references.Value.Add参数
    频道.回复参数
    return!loop()
    |放置参数->
    如果args=null,则
    空参数“args”
    elif references.Value.Count<大小
    idleReferences.Value.Enqueue参数
    其他的
    如果不是(references.Value.Remove args),则
    未找到invalidOp“引用”
    args.Dispose()
    return!loop()
    |处置频道->
    如果创建了references.isvalues,则
    参考文献。价值
    |>Seq.iter(fun args->args.Dispose())
    频道。回复收件箱
    }
    循环()))
    ///从池中返回SocketAsyncEventArgs实例。
    这个成员。获取()=
    agent.Value.PostAndReply(趣味频道->获取频道)
    ///将SocketAsyncEventArgs实例返回到池中。
    成员,请输入args=
    agent.Value.Post(放置参数)
    ///释放SocketAsyncEventArgsPool使用的所有资源。
    成员。处置()=
    (此:>IDisposable.Dispose())
    接口IDisposable与
    成员this.Dispose()=
    如果已创建agent.isvalues,则
    (agent.Value.PostAndReply(趣味频道->Dispose频道):>IDisposable.Dispose()
    
    邮箱(以及类似的结构)用于不使用锁的编程模型中,因为它们本质上是围绕异步处理构建的。(缺少共享的可变状态是该模型的另一个要求)

    Actor模型可以看作是一系列单线程微型应用程序,它们通过相互发送和接收数据进行通信。每个迷你应用程序一次只能由一个线程运行。这再加上缺少共享状态,使得锁变得不必要

    过程模型(大多数OO代码的核心是过程性的)使用线程级并发和对其他对象的同步调用。参与者模型改变了这一点——对象之间的调用(消息)是异步的,但每个对象都是完全同步的


    坦白地说,我不知道足够的F#来真正分析你的代码。看起来您确实在尝试在邮箱周围粘贴一个同步外壳,我想知道这是否是最好的做法(与完全采用邮箱模型相比)。在您的实现中,似乎您正在使用它来替换锁。

    对于问题的第一部分:

    MailboxProcessor类是一个在自己的线程上运行的消息队列。你可以发个短信 从任何线程异步或同步发送到MailboxProcessor


    这种模型允许线程之间通过消息传递进行通信,而不是使用锁/互斥锁/ipc机制。

    你知道你是绝对正确的。当我可以传递函数时,我没有理由等待args对象。无论如何,需要args对象的函数都是异步的。在这个模型中,最好说它允许参与者之间的通信,而不是线程之间的通信。参与者可以由任意线程提供服务,但通常保证一次只能由单个线程提供服务。参与者和线程之间缺乏1:1的关系,这使得系统可以扩展到比存在1:1映射时高得多的“进程”计数。