TryScan
을 사용하는 방법에 대한 예제를 찾으려고했지만 발견되지 않았습니다. 도와 주실 수 있습니까?F #에서 TryScan을 올바르게 사용하는 방법
내가 뭘하고 싶은지 (아주 단순화 된 예) : MailboxProcessor
은 두 종류의 메시지를받습니다.
첫 번째
GetState
은 현재 상태를 반환합니다.GetState
메시지가 상당히 자주 전송됩니다.기타
UpdateState
은 매우 비쌉니다. 인터넷에서 무언가를 다운로드하고 이에 따라 상태를 업데이트합니다.UpdateState
은 거의 호출되지 않습니다.
내 문제는 - 메시지 GetState
차단 및 UpdateState
을 이전하는 것은 제공 될 때까지 기다려야한다. 그래서 TryScan
을 사용하여 모든 메시지를 처리하려고했지만 운이 없었습니다.
내 예제 코드 : 코드를 실행하려고하면이 결과를 기다립니다 때문에
type Msg = GetState of AsyncReplyChannel<int> | UpdateState
let mbox = MailboxProcessor.Start(fun mbox ->
let rec loop state = async {
// this TryScan doesn't work as expected
// it should process GetState messages and then continue
mbox.TryScan(fun m ->
match m with
| GetState(chnl) ->
printfn "G processing TryScan"
chnl.Reply(state)
Some(async { return! loop state})
| _ -> None
) |> ignore
let! msg = mbox.Receive()
match msg with
| UpdateState ->
printfn "U processing"
// something very time consuming here...
async { do! Async.Sleep(1000) } |> Async.RunSynchronously
return! loop (state+1)
| GetState(chnl) ->
printfn "G processing"
chnl.Reply(state)
return! loop state
}
loop 0
)
[async { for i in 1..10 do
printfn " U"
mbox.Post(UpdateState)
async { do! Async.Sleep(200) } |> Async.RunSynchronously
};
async { // wait some time so that several `UpdateState` messages are fired
async { do! Async.Sleep(500) } |> Async.RunSynchronously
for i in 1..20 do
printfn "G"
printfn "%d" (mbox.PostAndReply(GetState))
}] |> Async.Parallel |> Async.RunSynchronously
, 당신은, GetState
메시지를 거의 처리되지 것을 볼 수 있습니다. 반면에 UpdateState
은 화재와 잊기에 효과적이므로 상태를 효과적으로 차단하지 못합니다. 나를 위해 작동
편집
현재 솔루션이 하나입니다 의견에
type Msg = GetState of AsyncReplyChannel<int> | UpdateState
let mbox = MailboxProcessor.Start(fun mbox ->
let rec loop state = async {
// this TryScan doesn't work as expected
// it should process GetState messages and then continue
let! res = mbox.TryScan((function
| GetState(chnl) -> Some(async {
chnl.Reply(state)
return state
})
| _ -> None
), 5)
match res with
| None ->
let! msg = mbox.Receive()
match msg with
| UpdateState ->
async { do! Async.Sleep(1000) } |> Async.RunSynchronously
return! loop (state+1)
| _ -> return! loop state
| Some n -> return! loop n
}
loop 0
)
반응 : 병렬 UpdateState
을 실행 다른 MailboxProcessor
또는 ThreadPool
와 아이디어가 중대하다, 그러나 나는 그것을 현재 필요로하지 않는다. 내가 원했던 것은 모두 GetState
메시지를 모두 처리 한 후 다른 메시지를 처리하는 것뿐이었습니다. 내가 처리하는 동안 걱정하지 않아 UpdateState
에이전트가 차단되었습니다.
// GetState messages are delayed 500 ms - see do! Async.Sleep(500)
// each UpdateState is sent after 200ms
// each GetState is sent immediatelly! (not real example, but illustrates the problem)
U 200ms <-- issue UpdateState
U processing <-- process UpdateState, it takes 1sec, so other
U 200ms 5 requests are sent; sent means, that it is
U 200ms fire-and-forget message - it doesn't wait for any result
and therefore it can send every 200ms one UpdateState message
G <-- first GetState sent, but waiting for reply - so all
previous UpdateState messages have to be processed! = 3 seconds
and AFTER all the UpdateState messages are processed, result
is returned and new GetState can be sent.
U 200ms
U 200ms because each UpdateState takes 1 second
U 200ms
U processing
U
U
U
U
U processing
G processing <-- now first GetState is processed! so late? uh..
U processing <-- takes 1sec
3
G
U processing <-- takes 1sec
U processing <-- takes 1sec
U processing <-- takes 1sec
U processing <-- takes 1sec
U processing <-- takes 1sec
U processing <-- takes 1sec
G processing <-- after MANY seconds, second GetState is processed!
10
G
G processing
// from this line, only GetState are issued and processed, because
// there is no UpdateState message in the queue, neither it is sent
'TryScan' 호출 후에'|> ignore'를한다는 사실은 당신이 API를 잘못 사용하고 있다는 사실을 경고해야합니다. (지금 완전한 대답을위한 시간이 없어, 누군가가 나를 때릴 수 있기를 바랍니다.) – Brian
나는 그것을 잘못된 방식으로 사용한다는 것을 알고 있습니다. 그러나 나는 그것을 전혀 사용하는 것에 대해 어떤 게시물도 찾지 못했습니다. – stej
'TryScan'과'Scan'의 요점은 메시지를 기다리는 것이고 수신되지 않으면 타임 아웃이라고 생각합니다. 두 가지의 유일한 차이점은 제한 시간 동안 TryScan에서 옵션이 반환되는 반면 Scan에서 예외가 발생한다는 것입니다. – gradbot