FsXaml uygulamasında eşzamansız ilerleme çubuğu

0

Soru

F# (FsXaml / Code Behind) uygulamamda, C# ' da yaptığım gibi bir arka plan çalışanı kullanmadan bir ilerleme çubuğu kullanmak istiyorum. İnternetteki bir makaleye dayanarak (bağlantı burada), eşzamansız iş akışlarını kullanmaya çalıştım.

Yukarıda belirtilen makaledeki örneklere dayanarak (bir dereceye kadar) kod oluşturdum, ancak beklediğim gibi çalışmadı. Geçerli iş parçacığı (UI iş parçacığı) hala async kodu yokmuş gibi engellendi. Arka plan iş parçacığına geçiş gerçekleşmez. İlerleme çubuğu ancak uzun süren işlem tamamlandıktan sonra etkinleştirilir. onThreadPool işlevinin kaldırılmasının hiçbir etkisi yoktur.

Sorum şu: Kodumda yanlış olan nedir ve nasıl düzeltilir?

type MainWindowXaml = FsXaml.XAML<"XAMLAndCodeBehind/MainWindow.xaml">

type MainWindow() as this =

    inherit MainWindowXaml()

    //....some code....

    let ButtonClick _ = 
   
        //....some code....
       
        let longRunningOperation() = //....some long running operation (reading from Google Sheets)....            
             
        let progressBar() = this.ProgressBar.IsIndeterminate <- true     

        let doBusyAsync progress operation =  
            progress
            async
                {   
                  do! operation
                }
            |> Async.StartImmediate 
    
        let onThreadPool operation =
            async
                {    
                  let context = System.Threading.SynchronizationContext.Current
                  do! Async.SwitchToThreadPool()
                  let! result = operation
                  do! Async.SwitchToContext context
                  return result
                } 
    
        let asyncOperation progress operation =   
            async { operation } 
            |> onThreadPool
            |> doBusyAsync progress 
    
        (progressBar(), longRunningOperation()) ||> asyncOperation 
      
    do
        //....some code....
        this.Button.Click.Add ButtonClick
asynchronous f# fsxaml
2021-11-23 23:13:28
2

En iyi cevabı

3

Kodunuzda bir takım yanlışlıklar var.

  • Öncelikle, progressBar(), longRunningOperation() aslında uzun süren operasyonu çağırıyorsunuz ve bu yüzden her şey burada yürütülüyor. (Tamamlanmamış örneğinizden tahmin edebildiğim kadarıyla, bu sadece bir işlev çağrısıdır, başka bir eşzamansız işlem değildir).

  • Daha sonra sonuçları iletirsiniz operation ve progress etrafta, ama bunlar sadece unit aslında hiçbir şey yapmayan değerler.

  • Sonuç olarak, zaman uyumsuz işlem async { operation } geçtiğin onThreadPool hiç bir şey yapmaz.

  • İçinde doBusyAsync kullandığınız Async.StartImmediate işlemi engelleyici bir şekilde çalıştırmak için (bu, bazı gerçek işlemleri çalıştırıyor olsa bile iş parçacığını engeller).

  • Engellemenin yanı sıra, buna da ihtiyacınız yok async { do! operation } çünkü bu sadece eşdeğerdir operation.

Özetle, kodunuz bir şekilde çok karmaşıklaştı. Bunu ilk adım olarak çok basit bir şeye basitleştirmelisiniz. Bunu denemek için doğru kuruluma sahip değilim, ancak aşağıdaki gibi bir şeyin hile yapması gerektiğini düşünüyorum:

let ButtonClick _ = 
  let longRunningOperation() = 
    // some long-running operation

  let asyncOperation() = async {
    // Start the progress bar here
    let context = System.Threading.SynchronizationContext.Current
    do! Async.SwitchToThreadPool()
    let result = longRunningOperation()
    do! Async.SwitchToContext context
    // Display the 'result' in your user interface
    // Stop the progress bar here
  }

  Async.Start(asyncOperation)

Tüm işe yaramaz işlevleri ve parametre aktarımını kaldırdım ve mümkün olduğunca basitleştirdim-bu sadece doğrudan çağrılan uzun süren işleminizdir. async bir kez iş parçacığı havuzuna geçer. Sonucunuzu alırsınız ve orijinal içeriğe geri döndükten sonra bunu kullanıcı arabiriminizde görüntüleyebilmelisiniz. İdeal olarak, tercih yapmak longRunningOperation kendisi eşzamansız (ve bunu kullanarak çağırın let! ancak yukarıdakiler işe yaramalı.

2021-11-24 00:15:43
0

Özetlemek gerekirse, Tomáš Petříček'in kodunu Jim Foye'nin yorumuna dayanarak (UI iş parçacığına geri dönme hakkında) uzun süren işlemle ilgili kodla genişlettim. Kod şimdi bir cazibe gibi çalışıyor. Nazik ve ayrıntılı cevabı için Tomáš Petříček'e teşekkür ederim.

    let low = string (this.TextBox2.Text)
    let high = string (this.TextBox3.Text)
    let path = string (this.TextBox4.Text)

    (* longRunningOperation() replaced by textBoxString4() and textBoxString3() 
       based on the comment by Jim Foye
    
    let longRunningOperation() = 
        async
            {
              match textBoxString4 low high >= 0 with
              | false -> this.TextBox1.Text <- textBoxString3 low high path 
              | true  -> this.TextBox1.Text <- "Chybný rozdíl krajních hodnot"        
            }
    *)

    let textBoxString4() = 
        async
            {
              let result = textBoxString4 low high
              return result
            }                  
                           
    let textBoxString3() =        
        async
            {
              //the actual long running operation (reading data 
              //from Google Sheets)
              let result = textBoxString3 low high path 
              return result
            }  

    let asyncOperation() = 
        async
            {
              let context = System.Threading.SynchronizationContext.Current
              this.ProgressBar2.IsIndeterminate <- true
              do! Async.SwitchToThreadPool()
              (*let! result = longRunningOperation() throws an exception 
              "The calling thread cannot access this object because
               a different thread owns it." 
              *)
              let! result4 = textBoxString4()  
              let! result3 = textBoxString3()  
              do! Async.SwitchToContext context
              match result4 >= 0 with
              | false -> this.TextBox1.Text <- result3
              | true  -> this.TextBox1.Text <- "Chybný rozdíl krajních hodnot" 
              this.ProgressBar2.IsIndeterminate <- false
            } 
    Async.StartImmediate(asyncOperation())//not working with Async.Start
                                             
2021-11-24 18:29:36

Diğer dillerde

Bu sayfa diğer dillerde

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................