简体   繁体   English

MailboxProcessor类型是锁的替代品吗?

[英]Is the MailboxProcessor type a replacement for locks?

I have been slowly examining all of the features that F# brings to the table. 我一直在慢慢研究F#带来的所有功能。 One that has particularly piqued my interest is the MailboxProcessor . 引起我兴趣的是MailboxProcessor

  1. The equivalent of this in C# would most likely use locks. 在C#中相当于这个很可能使用锁。 Can we consider the MailboxProcessor as a replacement for locks? 我们可以将MailboxProcessor视为锁的替代品吗?
  2. In the following example, am I doing anything particularly naive or can you see anything that might be improved? 在下面的例子中,我做了什么特别天真的事情,或者你能看到任何可以改进的东西吗?


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()

Mailboxes (and similar constructs) are used in programming models that don't use locks, as they're inherently built around asynchronous processing. 邮箱(和类似的结构)用于不使用锁的编程模型,因为它们本身是围绕异步处理构建的。 (Lack of shared mutable state is another requirement of this model). (缺乏共享可变状态是该模型的另一个要求)。

The Actor model can be thought of as a series of single-threaded mini-applications that communicate by sending and receiving data from each other. Actor模型可以被认为是一系列单线程迷你应用程序,它们通过相互发送和接收数据进行通信。 Each mini-application will only be run by a single thread at a time. 每个迷你应用程序一次只能由一个线程运行。 This, combined with the lack of shared state, renders locks unnecessary. 这与缺乏共享状态相结合,使锁定变得不必要。

Procedural models (and most OO code is, at its heart, procedural), use thread-level concurrency, and synchronous calls to other objects. 程序模型(以及大多数OO代码,其核心是程序性的),使用线程级并发,以及对其他对象的同步调用。 The Actor model flips this around - calls (messages) between objects are asynchronous, but each object is completely synchronous. Actor模型翻转它 - 对象之间的调用(消息)是异步的,但每个对象是完全同步的。

I don't know enough F# to really analyze your code, frankly. 坦率地说,我不太了解F#来真正分析你的代码。 It does look like you're trying to stick a synchronous-looking shell around your mailbox, and I wonder if that's really the best thing to do (vs. embracing the mailbox model fully). 它确实看起来像你试图在你的邮箱周围粘贴一个同步外壳,我想知道这是否真的是最好的事情(完全接受邮箱模型)。 In your implementation, it does appear that you're using it as a replacement for a lock. 在您的实现中,看起来您确实使用它作为锁的替代品。

To first part of your question: 问题的第一部分:

The MailboxProcessor class is a message queue running on its own thread. MailboxProcessor类是在其自己的线程上运行的消息队列。 You may send an message to the MailboxProcessor from any thread as asynchronously as synchronously. 您可以从任何线程向异步发送消息到MailboxProcessor同步。

Such model allows to communicate between threads through message passing instead of using locks/mutexes/ipc mechanics. 这种模型允许通过消息传递而不是使用lock / mutexes / ipc mechanics在线程之间进行通信。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM