Frage

Ich möchte das Konzept eines Ports des CCR -Frameworks in F# implementieren (da CCR für .NET 4.0 nicht offiziell unterstützt wird). Ich weiß, dass man das verwenden kann Mailboxprozessor Klasse in F#, um dies zu tun. Dies funktioniert perfekt für einfache Erhalten Schiedsrichter, aber ich brauche das Konzept der Einschränken Arbiter, dh ich möchte steuern, welche Nachrichten ausschließlich verarbeitet werden und welche gleichzeitig verarbeitet werden. Bisher habe ich keine Ahnung, dass ich dies in F# umsetzen kann, und ich wäre dankbar für Ihre Hilfe.

War es hilfreich?

Lösung

Ich bin mit CCR nicht sehr vertraut, aber ich werde versuchen zu antworten - mein Verständnis ist das Verschangen Sie Arbiter verhält sich ein bisschen wie ReaderWriterLock. Das heißt, Sie können einige Vorgänge angeben, die parallel (Lesevorgänge) und einige exklusive Operationen ausgeführt werden können.

Der folgende Agent ist eine Möglichkeit, es zu implementieren (nicht getestet, aber tippen Sie Schecks ein :-)). Der Agent enthält zwei Operationen, die für die öffentliche Verwendung bestimmt sind. Der letzte ist intern:

type Message<'T> =
  | PerformReadOperation of ('T -> Async<unit>)
  | PerformWriteOperation of ('T -> Async<'T>)
  | ReadOperationCompleted
  • Durch Senden des Agenten PerformReadOperation, Sie geben ihm eine Operation, die (einmal) mit dem Zustand und möglicherweise parallel zu anderen Lesevorgängen ausgeführt werden sollte.

  • Durch Senden des Agenten PerformWriteOperation, Sie geben ihm einen Vorgang, der einen neuen Zustand berechnet und nach Abschluss aller gelesenen Operationen ausgeführt werden muss. (Wenn Sie mit unveränderlichen Zustand arbeiten würden, würde dies die Dinge einfacher machen - Sie müssten nicht warten, bis die Leser abgeschlossen sind! Aber die folgende Implementierung implementiert das Warten).

Der Agent beginnt mit einem Ausgangszustand:

let initial = // initial state

Und der Rest des Agenten wird mit zwei Schleifen implementiert:

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)

Andere Tipps

Nur um die vorgeschlagene Lösung von Tomas hinzuzufügen, möchten Sie die Nachricht "ReadOperation Completed" nicht an den Verbraucher des Mail -Feldes mitteilen (da diese Nachricht intern ist und in der aktuellen Implementierung von einem Verbraucher des Mailboxs gesendet werden kann) Ein separates Mailbox kann in der Hauptverarbeitungsfunktion des Hauptpostfelds erstellt werden, die zwei Nachrichten akzeptiert: ReadOperationCompleted und WaitForReadCompleted (dieser wird mit postasyncreply vom Haupt -Mailbox verwendet) Die Operationen sind abgeschlossen. Auch die durch "Reads" dargestellte "Lesen" wird in dieses neue interne Mailbox verschoben, da dieser Status von diesem internen Mailbox eingekapselt wird.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top