无法使用邮箱处理器 (F#) 保持状态
Unable to keep state with mailbox processor (F#)
我正在尝试创建一个字符串列表,它在邮箱处理器的帮助下逐渐异步插入元素。但是我没有得到想要的输出。
我几乎遵循了 https://fsharpforfunandprofit.com/posts/concurrency-actor-model/ 中的代码
但是它似乎没有按我的预期工作。我的代码如下:
type TransactionQueue ={
queue : string list
} with
static member UpdateState (msg : string) (tq : TransactionQueue) =
{tq with queue = (msg :: tq.queue)}
static member Agent = MailboxProcessor.Start(fun inbox ->
let rec msgLoop (t : TransactionQueue) =
async{
let! msg = inbox.Receive()
let newT = TransactionQueue.UpdateState msg t
printfn "%A" newT
return! msgLoop newT
}
msgLoop {queue = []}
)
static member Add i = TransactionQueue.Agent.Post i
[<EntryPoint>]
let main argv =
// test in isolation
printfn "welcome to test"
let rec loop () =
let str = Console.ReadLine()
TransactionQueue.Add str
loop ()
loop ()
0
我一直得到的结果只是最新输入的列表,不保留状态。因此,如果我输入 "a" 然后 "b" 然后 "c" 队列将只有值 "c" 而不是 "a";"b";"c"
任何帮助或指点将不胜感激!
就像 C# Properties一样,你的Agent
实际上是一个属性,因此表现得像一个带有void
参数的方法。这就是为什么每次访问 Agent
属性 都会得到一个新代理。
在惯用的 F# 中,实现代理时有两种风格。如果不需要很多agent实例,写一个模块,把agent-related的东西封装在里面就可以了。否则,应使用 OOP 样式。
样式 #1 的代码
module TransactionQueue =
type private Queue = Queue of string list
let private empty = Queue []
let private update item (Queue items) = Queue (item :: items)
let private agent = MailboxProcessor.Start <| fun inbox ->
let rec msgLoop queue = async {
let! msg = inbox.Receive ()
return! queue |> update msg |> msgLoop
}
msgLoop empty
let add item = agent.Post item
[<EntryPoint>]
let main argv =
// test in isolation
printfn "welcome to test"
let rec loop () =
let str = Console.ReadLine()
TransactionQueue.add str
loop ()
loop ()
样式 #2 的代码
type Queue = Queue of string list with
static member Empty = Queue []
static member Update item (Queue items) =
Queue (item :: items)
type Agent () =
let agent = MailboxProcessor.Start <| fun inbox ->
let rec msgLoop queue = async {
let! msg = inbox.Receive ()
return! queue |> Queue.Update msg |> msgLoop
}
msgLoop Queue.Empty
member this.Add item = agent.Post item
[<EntryPoint>]
let main argv =
// test in isolation
printfn "welcome to test"
let agent = new Agent ()
let rec loop () =
let str = Console.ReadLine()
agent.Add str
loop ()
loop ()
请注意 Single-case union types 用于 Queue
类型。
我正在尝试创建一个字符串列表,它在邮箱处理器的帮助下逐渐异步插入元素。但是我没有得到想要的输出。
我几乎遵循了 https://fsharpforfunandprofit.com/posts/concurrency-actor-model/ 中的代码 但是它似乎没有按我的预期工作。我的代码如下:
type TransactionQueue ={
queue : string list
} with
static member UpdateState (msg : string) (tq : TransactionQueue) =
{tq with queue = (msg :: tq.queue)}
static member Agent = MailboxProcessor.Start(fun inbox ->
let rec msgLoop (t : TransactionQueue) =
async{
let! msg = inbox.Receive()
let newT = TransactionQueue.UpdateState msg t
printfn "%A" newT
return! msgLoop newT
}
msgLoop {queue = []}
)
static member Add i = TransactionQueue.Agent.Post i
[<EntryPoint>]
let main argv =
// test in isolation
printfn "welcome to test"
let rec loop () =
let str = Console.ReadLine()
TransactionQueue.Add str
loop ()
loop ()
0
我一直得到的结果只是最新输入的列表,不保留状态。因此,如果我输入 "a" 然后 "b" 然后 "c" 队列将只有值 "c" 而不是 "a";"b";"c"
任何帮助或指点将不胜感激!
就像 C# Properties一样,你的Agent
实际上是一个属性,因此表现得像一个带有void
参数的方法。这就是为什么每次访问 Agent
属性 都会得到一个新代理。
在惯用的 F# 中,实现代理时有两种风格。如果不需要很多agent实例,写一个模块,把agent-related的东西封装在里面就可以了。否则,应使用 OOP 样式。
样式 #1 的代码
module TransactionQueue =
type private Queue = Queue of string list
let private empty = Queue []
let private update item (Queue items) = Queue (item :: items)
let private agent = MailboxProcessor.Start <| fun inbox ->
let rec msgLoop queue = async {
let! msg = inbox.Receive ()
return! queue |> update msg |> msgLoop
}
msgLoop empty
let add item = agent.Post item
[<EntryPoint>]
let main argv =
// test in isolation
printfn "welcome to test"
let rec loop () =
let str = Console.ReadLine()
TransactionQueue.add str
loop ()
loop ()
样式 #2 的代码
type Queue = Queue of string list with
static member Empty = Queue []
static member Update item (Queue items) =
Queue (item :: items)
type Agent () =
let agent = MailboxProcessor.Start <| fun inbox ->
let rec msgLoop queue = async {
let! msg = inbox.Receive ()
return! queue |> Queue.Update msg |> msgLoop
}
msgLoop Queue.Empty
member this.Add item = agent.Post item
[<EntryPoint>]
let main argv =
// test in isolation
printfn "welcome to test"
let agent = new Agent ()
let rec loop () =
let str = Console.ReadLine()
agent.Add str
loop ()
loop ()
请注意 Single-case union types 用于 Queue
类型。