Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/wordpress/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asynchronous Async.TryCancelled不能与Async.RunSynchronously一起使用_Asynchronous_F#_Agent_Mailboxprocessor - Fatal编程技术网

Asynchronous Async.TryCancelled不能与Async.RunSynchronously一起使用

Asynchronous Async.TryCancelled不能与Async.RunSynchronously一起使用,asynchronous,f#,agent,mailboxprocessor,Asynchronous,F#,Agent,Mailboxprocessor,我尝试创建一个基于用户交互更新UI的代理。如果用户单击按钮,GUI应该被刷新。模型的准备工作需要很长时间,因此,如果用户单击其他按钮,则需要取消准备工作并开始新的准备工作 到目前为止,我所拥有的: open System.Threading type private RefreshMsg = | RefreshMsg of AsyncReplyChannel<CancellationTokenSource> type RefresherAgent() = le

我尝试创建一个基于用户交互更新UI的代理。如果用户单击按钮,GUI应该被刷新。模型的准备工作需要很长时间,因此,如果用户单击其他按钮,则需要取消准备工作并开始新的准备工作

到目前为止,我所拥有的:

open System.Threading
type private RefreshMsg = 
    | RefreshMsg of AsyncReplyChannel<CancellationTokenSource>

type RefresherAgent() =  
    let mutable cancel : CancellationTokenSource = null

    let doSomeModelComputation i =
        async { 
          printfn "start %A" i
          do! Async.Sleep(1000)
          printfn "middle %A" i
          do! Async.Sleep(1000)
          printfn "end %A" i
        }
    let mbox = 
        MailboxProcessor.Start(fun mbx ->
            let rec loop () = async {
                let! msg = mbx.Receive()
                match msg with
                | RefreshMsg(chnl) ->
                    let cancelSrc = new CancellationTokenSource()
                    chnl.Reply(cancelSrc)
                    let update = async {
                                    do! doSomeModelComputation 1
                                    do! doSomeModelComputation 2
                                    //do! updateUI // not important now
                                 }
                    let cupdate = Async.TryCancelled(update, (fun c -> printfn "refresh cancelled"))
                    Async.RunSynchronously(cupdate, -1, cancelSrc.Token)
                    printfn "loop()"
                    return! loop()
            }
            loop ())
    do
        mbox.Error.Add(fun exn -> printfn "Error in refresher: %A" exn)
    member x.Refresh() = 
        if cancel <> null then
            // I don't handle whether the previous computation finished
            // I just cancel it; might be 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()
现在我想,这可能是有道理的,因为代理运行的线程是被中断的,对吗?但是,我如何实现期望的行为

我需要取消代理内部的异步工作流,以便代理可以继续使用新消息。为什么要使用邮箱处理器?因为保证只有一个线程试图创建UI模型,所以我节省了资源

假设我通过从多个web服务下载数据来创建UI模型,这就是我使用异步调用的原因。当用户更改组合并选择其他选项时,我希望停止查询webservices=使用旧值取消异步调用,并希望使用新值创建新的基于模型的od web服务调用


我也欢迎任何可以用来代替我的解决方案并能解决我问题的建议。

我很难理解您想要实现的目标。但这也许无关紧要——错误只是说您正在使用RunSynchronously执行的工作流已被取消RunSynchronously将引发异常——因此您可以将此调用包装到一个try match块中,忽略OC异常

一个更好的选择可能是重构你的cupdate,并在其中尝试匹配——如果你直接捕获OC异常,你甚至可以将in-TryCancelled引入其中

let update = 
   async {
      try
         do! doSomeModelComputation 1
         do! doSomeModelComputation 2
      with
      | :? OperationCanceledException -> 
           printfn "refresh cancelled"
   }
Async.RunSynchronously(update, -1, cancelSrc.Token)

但我仍然不明白你为什么要同步进行这项工作,只是添加了一段话来更好地解释背景。你说抓住exc是一个解决方案是对的,但我希望有一个更好的解决方案。除了TryCancelled和RunSynchronously之外,可能还有来自Async的其他方法的组合。我在回答中添加了一个建议。。。我无法测试这一点,但我认为它应该像预期的那样工作,对我有效,没有其他人添加其他解决方案,因此。。接受:最后我得到了@tomasp的评论
let update = 
   async {
      try
         do! doSomeModelComputation 1
         do! doSomeModelComputation 2
      with
      | :? OperationCanceledException -> 
           printfn "refresh cancelled"
   }
Async.RunSynchronously(update, -1, cancelSrc.Token)