1

この質問はAsync.TryCancelledがAsync.RunSynchronouslyで機能しないことに基づいています。これは複雑に見えるので、解決しようとする単純な部分を切り取ります。

私がこの関数を持っているとしましょう:

let prepareModel () = 
    async {
        // this might take a lot of time (1-50seconds)
        let! a = ...
        let! b = ...
        let! res = combine a b
        return res
    }
 let updateUI model =
    runOnUIThread model

prepareModelユーザーに表示する必要のあるデータを準備します。updateUIUIを更新します(古いコントロールを削除し、新しいデータに基づいて新しいctlを作成します)。

質問:prepareModelいつでもキャンセルできるように、2つの関数をどのように呼び出す必要がありますか?

流れは

  • ユーザーが[更新]をクリックします
    • prepareModel(1)開始され、非同期で実行されているため、UIは応答性が高く、ユーザーはアプリケーションを操作できます
  • ユーザーがデータを変更し、[更新]をもう一度クリックします
    • prepareModel(1)fromがキャンセルされ、new prepareModel(2)が開始されます
  • ユーザーがデータを変更し、[更新]をもう一度クリックします
    • prepareModel(2)がキャンセルされ、新しいprepareModel(3)が開始されます
    • ..
    • prepareModel(n)終了
    • updateUIUIスレッドで実行され、UIを再描画します

(私の最初の解決策は、1つだけが実行されるMailboxProcessorことを保証することに基づいています。Async.TryCancelledはAsync.RunSynchronouslyでは機能しませんが、これを実験したので、バグはありません)prepareModel

4

1 に答える 1

5

考えられるアプローチの1つは、を使用してバックグラウンドで非同期にワークフローを開始することですAsync.Start(その後、キャンセル可能である必要があります)。最後にUIを再描画するAsync.SwitchToContextには、ワークフローの最後の部分がUIで実行されることを確認するために使用できます。これがスケッチです:

// Capture current synchronization context of the UI
// (this should run on the UI thread, i.e. when starting)
let syncContext = System.Threading.SynchronizationContext.Current

// Cancellation token source that is used for cancelling the
// currently running workflow (this can be mutable)
let cts = ref (new CancellationTokenSource())

// Workflow that does some calculations and then updates gui
let updateModel () =   
    async {  
        // this might take a lot of time (1-50seconds)  
        let! a = ...  
        let! b = ...  
        let! res = combine a b 

        // switch to the GUI thread and update UI
        do! Async.SwitchToContext(syncContext)
        updateUserInterface res
    }  

// This would be called in the click handler - cancel the previous
// computation, creat new cancellation token & start the new one
cts.Cancel()
cts := new CancellationTokenSource()
Async.Start(updateModel(), cts.Token)
于 2012-03-08T10:29:20.577 に答える