asynchronous - Async.TryCancelled doesn't work with Async.RunSynchronously -
i try create agent updates ui based on user interaction. if user clicks on button, gui should refreshed. preparation of model takes long time, desirable if user clicks on other button, preparation cancelled , new 1 started.
what have far:
open system.threading type private refreshmsg = | refreshmsg of asyncreplychannel<cancellationtokensource> type refresheragent() = let mutable cancel : cancellationtokensource = null let dosomemodelcomputation = async { printfn "start %a" do! async.sleep(1000) printfn "middle %a" do! async.sleep(1000) printfn "end %a" } let mbox = mailboxprocessor.start(fun mbx -> let rec loop () = async { let! msg = mbx.receive() match msg | refreshmsg(chnl) -> let cancelsrc = new cancellationtokensource() chnl.reply(cancelsrc) let update = async { do! dosomemodelcomputation 1 do! dosomemodelcomputation 2 //do! updateui // not important } let cupdate = async.trycancelled(update, (fun c -> printfn "refresh cancelled")) async.runsynchronously(cupdate, -1, cancelsrc.token) printfn "loop()" return! loop() } loop ()) mbox.error.add(fun exn -> printfn "error in refresher: %a" exn) member x.refresh() = if cancel <> null // don't handle whether previous computation finished // cancel it; might improved cancel.cancel() cancel.dispose() cancel <- mbox.postandreply(fun reply -> refreshmsg(reply)) printfn "x.refresh end" //sample let agent = refresheragent() agent.refresh() system.threading.thread.sleep(1500) agent.refresh()
i return cancellationtokensource
each request , store in mutable variable (the x.refresh() thread safe, called on ui thread). if refresh() called first time, cancellation source returned. if refresh() called second time, call cancel should abort async task run through async.runsynchronously.
however, exception raised. output sample
x.refresh end start 1 middle 1 end 1 refresh cancelled error in refresher: system.operationcanceledexception: operation canceled. @ microsoft.fsharp.control.asyncbuilderimpl.commit[a](result`1 res)
now think this, might make sense, because thread on agent runs, interrputed, right? but, how achieve desired behaviour?
i need cancel async workflow inside agent, agent can continue consuming new messages. why use mailbox processor? cause guaranteed 1 thread trying create ui model, save resources.
let's suppose create ui model downloading data several web services, that's why use async call. when user changes combo , select other option, want stop querying webservices (= cancel async calls) old value , want create new model base od web services call new value.
any suggestion can use instead of solution , solve problem, welcome.
i have difficulties in trying understand want achieve. maybe not matter - error says workflow executing runsynchronously
canceled (runsynchronously throw exception) - can wrap call try-match block , ignore oc-exception
a better option might refactor cupdate , try-match inside of - can bring in trycancelled if catch oc-exceptions directly ;)
let update = async { try do! dosomemodelcomputation 1 do! dosomemodelcomputation 2 | :? operationcanceledexception -> printfn "refresh cancelled" } async.runsynchronously(update, -1, cancelsrc.token)
but still don't part why want synchronously
Comments
Post a Comment