简体   繁体   English

来自代理/邮箱处理器的通用回复?

[英]Generic reply from agent/mailboxprocessor?

I currently have an agent that does heavy data processing by constantly posting "work" messages to itself. 我目前有一个代理,它通过不断向自身发布“工作”消息来进行大量数据处理。

Sometimes clients to this agent wants to interrupt this processing to access the data in a safe manner. 有时,该代理的客户端希望中断此处理,以安全的方式访问数据。

For this I thought that posting an async to the agent that the agent can run whenever it's in a safe state would be nice. 为此,我认为将异步消息发布到代理以使代理只要处于安全状态就可以运行即可。 This works fine and the message looks like this: 这可以正常工作,并且消息看起来像这样:

type Message = |Sync of Async<unit>*AsyncReplyChannel<unit> 

And the agent processing simply becomes: 代理处理就变成:

match mailbox.Receive () with
| Sync (async, reply) -> async |> Async.RunSynchronously |> reply.Reply

This works great as long as clients don't need to return some value from the async as I've constrained the async/reply to be of type unit and I cannot use a generic type in the discriminated union. 只要我不需要将异步/回复限制为unit类型,并且我不能在已区分的联合中使用泛型类型,只要客户端不需要从异步返回一些值,这就很好用。

My best attempts to solve this has involved wrapper asyncs and waithandles, but this seems messy and not as elegant as I've come to expect from F#. 解决此问题的最佳尝试涉及包装器异步和等待处理程序,但这似乎很杂乱,并不像我从F#期望的那样优雅。 I'm also new to async workflows in F# so it's very possible that I've missed/misunderstood some concepts here. 我也是F#中异步工作流的新手,因此很可能我在这里错过/误解了一些概念。

So the question is; 所以问题是; how can I return generic types in a agent response? 如何在代理响应中返回泛型类型?

The thing that makes this difficult is that, in your current version, the agent would somehow have to calculate the value and then pass it to the channel, without knowing what is the type of the value. 造成这一困难的是,在您当前的版本中,代理将不得不以某种方式计算值,然后将其传递给通道,而不知道值的类型是什么。 Doing that in a statically typed way in F# is tricky. 在F#中以静态类型的方式执行此操作很棘手。

If you make the message generic, then it will work, but the agent will only be able to handle messages of one type (the type T in Message<T> ). 如果使消息通用的,那么它会工作,但代理仅能够处理一种类型(类型的消息TMessage<T>

An alternative is to simply pass Async<unit> to the agent and let the caller do the value passing for each specific type. 另一种选择是简单地将Async<unit>传递给代理,然后让调用者为每种特定类型传递值。 So, you can write message & agent just like this: 因此,您可以像这样编写消息和代理:

type Message = | Sync of Async<unit>

let agent = MailboxProcessor.Start(fun inbox -> async {
  while true do
    let! msg = inbox.Receive ()
    match msg with
    | Sync (work) -> do! work })

When you use PostAndReply , you get access to the reply channel - rather than passing the channel to the agent, you can just use it in the local async block: 使用PostAndReply ,您可以访问回复通道- PostAndReply将通道传递给代理,您可以在本地async块中使用它:

let num = agent.PostAndReply(fun chan -> Sync(async { 
  let ret = 42 
  chan.Reply(ret) }))

let str = agent.PostAndReply(fun chan -> Sync(async { 
  let ret = "hi"
  chan.Reply(ret) }))

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

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