반응형 UI를 사용하여 비동기 취소 가능 워크플로에서 데이터를 준비하는 올바른 방법

StackOverflow https://stackoverflow.com//questions/9615810

문제

이 질문은 다음을 기반으로 합니다. 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 사용자에게 표시되어야 하는 데이터를 준비합니다. updateUI UI를 새로 고칩니다(이전 컨트롤을 제거하고 새 데이터를 기반으로 새 ctls를 만듭니다).

질문: 두 함수를 어떻게 호출해야 합니까? prepareModel 언제든지 취소할 수 있나요?

흐름은

  • 사용자가 새로고침을 클릭함
    • prepareModel(1) 비동기적으로 시작되어 실행 중이므로 UI가 반응하고 사용자가 애플리케이션으로 작업할 수 있습니다.
  • 사용자가 데이터를 변경하고 다시 새로고침을 클릭합니다.
    • prepareModel(1) from이 취소되고 새로운 prepareModel(2)가 시작되었습니다
  • 사용자가 데이터를 변경하고 다시 새로고침을 클릭합니다.
    • prepareModel(2) 취소되고 새로 제공됩니다 prepareModel(3)이 시작되었습니다
    • ..
    • prepareModel(n) 완료
    • updateUI UI 스레드에서 실행되고 UI를 다시 그립니다.

(내 첫 번째 솔루션은 다음을 기반으로합니다. MailboxProcessor 이는 단 하나만 보장합니다. prepareModel 실행됩니다. 다음을 참조하세요. Async.TryCancelled가 Async.RunSynchronously와 작동하지 않습니다. 하지만 이것을 실험해 본 결과 버그가 없는 것은 아닙니다)

도움이 되었습니까?

해결책

한 가지 가능한 접근 방식은 다음을 사용하여 백그라운드에서 비동기적으로 워크플로를 시작하는 것입니다. 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)
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top