Question

Je veux mettre en œuvre le concept d'un port du cadre du CCR en F # (comme CCR est pas officiellement pris en charge pour .Net 4.0). Je sais que l'on peut utiliser le MailboxProcessor classe F # pour le faire. Cela fonctionne parfaitement pour simplement Recevoir Inquisiteurs mais je dois le concept de Interleave Arbiter, à savoir que je veux contrôler les messages sont traités exclusivement et qui sont traitées simultanément. Jusqu'à présent, j'ai aucune idée de mettre en œuvre ce en F # et je vous serais reconnaissant de votre aide.

Était-ce utile?

La solution

Je ne suis pas très familier avec CCR, mais je vais essayer de répondre - je crois comprendre que entrelacer arbitre se comporte un peu comme ReaderWriterLock. Autrement dit, vous pouvez spécifier certaines opérations qui peuvent être exécutées en parallèle (lit) et certaines opérations qui sont exclusives (écrit).

L'agent suivant est une façon de mettre en œuvre (non testé, mais les contrôles de type :-)). L'agent expose deux opérations qui sont destinés à un usage public. Le dernier est interne:

type Message<'T> =
  | PerformReadOperation of ('T -> Async<unit>)
  | PerformWriteOperation of ('T -> Async<'T>)
  | ReadOperationCompleted
  • En envoyant le PerformReadOperation agent, vous donnant une opération qui doit être exécutée (une fois) à l'aide de l'état et, éventuellement, en parallèle avec d'autres opérations de lecture.

  • En envoyant le PerformWriteOperation agent, vous donnant une opération qui calcule un nouvel état et doit être exécuté après toutes les opérations de lecture complètes. (Si vous travaillez avec l'état immuable, qui rendrait les choses plus simples - vous pas attendre les lecteurs complète Mais la mise en œuvre ci-dessous met en œuvre l'attente).

L'agent commence par un état initial:

let initial = // initial state

Et le reste de l'agent est mis en œuvre en utilisant deux boucles:

let interleaver = MailboxProcessor.Start(fun mbox ->

  // Asynchronously wait until all read operations complete
  let rec waitUntilReadsComplete reads = 
    if reads = 0 then async { return () }
    else mbox.Scan(fun msg ->
      match msg with
      | ReadOperationCompleted -> Some(waitUntilReadsComplete (reads - 1))
      | _ -> None)

  let rec readingLoop state reads = async {
    let! msg = mbox.Receive()
    match msg with
    | ReadOperationCompleted ->
        // Some read operation completed - decrement counter
        return! readingLoop state (reads - 1) 
    | PerformWriteOperation(op) ->
        do! waitUntilReadsComplete reads
        let! newState = op state
        return! readingLoop newState 0
    | PerformReadOperation(op) ->
        // Start the operation in background & increment counter
        async { do! op state
                mbox.Post(ReadOperationCompleted) }
        |> Async.Start
        return! readingLoop state (reads + 1) }
  readingLoop initial 0)

Autres conseils

Juste pour ajouter à la solution Tomas a suggéré, au cas où vous ne voulez pas exposer le message « ReadOperationCompleted » au consommateur de la boîte de messagerie (comme ce message est interne et la mise en œuvre actuelle peut être envoyée par tout consommateur de boîte aux lettres) une boîte de courrier séparé peut être créé à l'intérieur de la fonction principale du processeur de boîte de messagerie qui accepte deux messages: ReadOperationCompleted et WaitForReadCompleted (celui-ci sera utilisé avec PostAndAsyncReply par la principale boîte aux lettres) que la réponse à ce message ne viendra que lorsque toutes les opérations de lecture sont terminées. De plus, le compte « lire » représentée par « lit » sera déplacé à cette nouvelle boîte de courrier interne que cet état encapsuler par cette boîte de courrier interne.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top