F#,MailboxProcessor和Async运行缓慢?
背景。 我在想MailboxProcessor。其思想是将其用作某种状态机,在状态之间传递参数,然后退出。有些部分将进行异步通信,所以我在那里睡了一觉。 这是一个控制台应用程序,发布帖子没有任何作用,因为主线程退出并杀死它背后的所有东西。我主要在做一个邮差。 而且,我也试过不穿F#,MailboxProcessor和Async运行缓慢?,f#,mailboxprocessor,F#,Mailboxprocessor,背景。 我在想MailboxProcessor。其思想是将其用作某种状态机,在状态之间传递参数,然后退出。有些部分将进行异步通信,所以我在那里睡了一觉。 这是一个控制台应用程序,发布帖子没有任何作用,因为主线程退出并杀死它背后的所有东西。我主要在做一个邮差。 而且,我也试过不穿 let sleepWorkflow = async ,没有任何区别 问题。 (我可能做错了什么) Go24不是异步的。将RunSynchronously更改为StartImmediate没有明显的区别。结尾应该在Ge
let sleepWorkflow = async
,没有任何区别
问题。
(我可能做错了什么)
[<EntryPoint>]
let main argv =
let a = Mailbox.MessageBasedCounter.DoGo24 1
let a = Mailbox.MessageBasedCounter.DoFetch 1
let b = Mailbox.MessageBasedCounter.GetMe
let task i = async {
//Mailbox.MessageBasedCounter.DoGo24 1
let a = Mailbox.MessageBasedCounter.DoFetch i
return a
}
let stopWatch = System.Diagnostics.Stopwatch.StartNew()
let x =
[1..10]
|> Seq.map task
|> Async.Parallel
|> Async.RunSynchronously
stopWatch.Stop()
printfn "%f" stopWatch.Elapsed.TotalMilliseconds
printfn "a: %A" a
printfn "b: %A" b
printfn "x: %A" x
0 // return an integer exit code
[]
让主argv=
设a=Mailbox.MessageBasedCounter.DoGo24 1
设a=Mailbox.MessageBasedCounter.DoFetch 1
设b=Mailbox.MessageBasedCounter.GetMe
让任务i=异步{
//Mailbox.MessageBasedCounter.DoGo24 1
设a=Mailbox.MessageBasedCounter.DoFetch i
归还
}
让stopWatch=System.Diagnostics.stopWatch.StartNew()
设x=
[1..10]
|>Seq.map任务
|>异步并行
|>异步运行
秒表
printfn“%f”stopWatch.appeased.total毫秒
打印fn“a:%a”a
打印fn“b:%A”b
printfn“x:%A”x
0//返回整数退出代码
Mailbox.fs
module Mailbox
#nowarn "40"
type parserMsg =
| Go24 of int
| Done
| Fetch of int * AsyncReplyChannel<string>
| GetMe of AsyncReplyChannel<string>
type MessageBasedCounter () =
/// Create the agent
static let agent = MailboxProcessor.Start(fun inbox ->
// the message processing function
let rec messageLoop() = async{
let! msg = inbox.Receive()
match msg with
| Go24 n ->
let sleepWorkflow = async{
printfn "Go24, wait"
do! Async.Sleep 4000
MessageBasedCounter.DoDone() // POST Done.
printfn "go24 %d, end" n
return! messageLoop()
}
Async.RunSynchronously sleepWorkflow
| Fetch (i, repl) ->
let sync = async{
printfn "Fetch %d" i
do! Async.Sleep 1000
repl.Reply( "Reply Fetch " + i.ToString() ) // Reply to the caller
return! messageLoop()
}
Async.RunSynchronously sync
| GetMe (repl) ->
let sync = async{
printfn "GetMe"
repl.Reply( "GetMe" ) // Reply to the caller
return! messageLoop()
}
Async.RunSynchronously sync
| Done ->
let sync = async{
printfn "Done"
return! messageLoop()
}
Async.RunSynchronously sync
}
// start the loop
messageLoop()
)
// public interface to hide the implementation
static member DoDone () = agent.Post( Done )
static member DoGo24 (i:int) = agent.Post( Go24(i) )
static member DoFetch (i:int) = agent.PostAndReply( fun reply -> Fetch(i, reply) )
static member GetMe = agent.PostAndReply( GetMe )
模块邮箱
#诺瓦恩“40”
类型parserMsg=
|int的Go24
|完成
|获取int*AsyncReplyChannel
|AsyncReplyChannel的GetMe
键入MessageBasedCounter()=
///创建代理
静态let agent=MailboxProcessor.Start(有趣的收件箱->
//消息处理功能
让rec messageLoop()=异步{
let!msg=inbox.Receive()
配味精
|Go24 n->
让sleepWorkflow=async{
打印fn“Go24,等待”
do!Async.Sleep 4000
MessageBasedCounter.DoDone()//POST Done。
打印fn“go24%d,结束”n
return!messageLoop()
}
Async.RunSynchronously休眠工作流
|获取(i,repl)->
让同步=异步{
printfn“获取%d”i
do!Async.Sleep 1000
repl.Reply(“Reply Fetch”+i.ToString())//回复调用者
return!messageLoop()
}
Async.RunSynchronously同步
|GetMe(repl)->
让同步=异步{
printfn“GetMe”
repl.Reply(“GetMe”)//回复调用方
return!messageLoop()
}
Async.RunSynchronously同步
|完成->
让同步=异步{
打印fn“完成”
return!messageLoop()
}
Async.RunSynchronously同步
}
//开始循环
messageLoop()
)
//用于隐藏实现的公共接口
静态成员DoDone()=agent.Post(完成)
静态成员DoGo24(i:int)=agent.Post(Go24(i))
静态成员DoFetch(i:int)=agent.PostAndReply(有趣的回复->获取(i,回复))
静态成员GetMe=agent.PostAndReply(GetMe)
我不一定确定这是主要问题,但代理代码中的嵌套异步和Async.runsynchronously
看起来可疑
不需要创建嵌套的异步-只需直接调用match
子句主体中的异步操作即可:
// the message processing function
let rec messageLoop() = async{
let! msg = inbox.Receive()
match msg with
| Go24 n ->
printfn "Go24, wait"
do! Async.Sleep 4000
MessageBasedCounter.DoDone()
printfn "go24 %d, end" n
return! messageLoop()
| Fetch (i, repl) ->
(...)
除此之外,重要的是要了解代理只有一个实体计算实例在运行。因此,如果阻止代理的主体,所有其他操作都将排队
如果要在后台启动某些任务(如同步操作)并立即恢复代理,可以在主体内部使用Async.start
(但请确保在主体中递归调用主循环):
啊哈,谢谢你。我正试图恢复你所说的那个特工。看来我的错误是回电话了!异步内的messageLoop()。这并不能恢复代理。我使用外部异步作为解决方法,因为需要将Seq.map作为parallel。运行let x=[1..10]|>Seq.map Mailbox.MessageBasedCounter.DoFetch会在到达10之前中断程序。List.map运行到10时没有问题。只是一个有趣的时刻。
| Go24 n ->
// Create work item that will run in the background
let work = async {
printfn "Go24, wait"
do! Async.Sleep 4000
MessageBasedCounter.DoDone()
printfn "go24 %d, end" n }
// Queue the work in a thread pool to be processed
Async.Start(work)
// Continue the message loop, waiting for other messages
return! messageLoop()