6

MailboxProcessor が破棄された (または停止された) ときに PostAndAsyncReply をすぐに返すことは可能ですか? または、デッドロックを作成せずに PostAndReply メソッドを安全に使用する方法に関する「パターン」/ベストプラクティスはありますか?

現在、MailboxProcessor が破棄されたときに PostAndAsyncReply が返されないという問題があります。私は待つことができないので、タイムアウトパラメータを使用することはオプションではありません (また、あまりにも多くの要因に依存するため、合理的なタイムアウトを選択することは非常に困難または不可能です)。

  [<Test>]
  let ``waiting for a reply from a disposed agent``() =
    use server = MailboxProcessor.Start(fun inbox -> async {
      ()
    })

    (server :> System.IDisposable).Dispose()

    server.PostAndReply (fun reply -> reply) // <- deadlock
    |> ignore)

編集: 私が見た MailboxProcessors のほとんどの例 (MSDN のものを含む) は、MailboxProcessors を破棄することさえ気にしません。また、MSDN では、破棄されたときに MailboxProcessors がどのように反応するかについて説明していません。処分する必要はありませんか?

4

1 に答える 1

6

保留中のPostAndReply呼び出しをキャンセルする組み込みのサポートはありませんが、これを実装できます。廃棄の際は、メールボックス本体を で包むことができますtry .. finally。ブロックではfinally、メールボックス プロセッサが停止したことを何らかの方法で通知できます。以下は、これにキャンセル トークン ソースを使用します。

let disposed = new System.Threading.CancellationTokenSource()
let server = MailboxProcessor<AsyncReplyChannel<obj>>.Start(fun inbox -> 
  async { 
    try 
      // The normal body of the mailbox processor goes here
      do! Async.Sleep(1000)
      printfn "done"
    finally 
      // Cancel all pending calls post and reply
      disposed.Cancel()
   })

// Dispose the mailbox processor    
(server :> System.IDisposable).Dispose()

// When sending message, we use 'StartAsTask' and set a cancellation token,
// so that the work is stopped when the mailbox processor finishes
let wait = server.PostAndAsyncReply(fun reply -> reply)
let task = Async.StartAsTask(wait, cancellationToken = disposed.Token)
printfn "%A" task.Result

次の 2 つの点に注意してください。

  • メールボックス プロセッサが長時間の作業を実行している場合 (スリープ状態など)、これが完了した後に破棄が行われます (これは非同期ワークフローの性質によるもので、計算を強制的にキャンセルすることはありません)。

  • 最後にタスクを開始するStartAsTask代わりに使用する必要がありました。RunSynchronously何らかの理由で (はっきりとはわかりませんが)、 を使用RunSynchronouslyしても計算がキャンセルされないようです。

内部で使用し、同様のインターフェースを公開し、この機能を追加するクラスでこれを簡単にラップできますがMailboxProcessor、それは単一の答えには少し多すぎます!

に関するあなたの質問に答えるためにDispose、私は動作が何であるか完全にはわかりませんが、メールボックス プロセッサを破棄すると、メッセージが到着したことを知らせるために使用される内部AutoResetEvent(ソース コードを参照) が破棄されます。これは、メールボックス プロセッサがそれ以上のメッセージを受け入れないことを意味しているだけだと思います。

于 2013-08-19T13:23:59.463 に答える