在我的F# (FsXaml/代碼隱藏)應用程式中,我想使用進度條,而不像在 C# 中那樣使用后臺作業程式。根據互聯網上的一篇文章(鏈接在這里),我嘗試使用異步作業流。
我根據(在某種程度上)上述文章中的示例創建了代碼,但它沒有按我預期的那樣作業。當前執行緒(UI 執行緒)仍然被阻塞,就好像那里沒有異步代碼一樣。不會切換到后臺執行緒。只有在長時間運行的操作完成后才會激活進度條。洗掉onThreadPool函式沒有任何效果。
我的問題是:我的代碼有什么問題以及如何使其正確?
由于 Stackoverflow 不鼓勵感謝評論,我在此提前感謝任何人的回答。
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
uj5u.com熱心網友回復:
您的代碼有很多問題。
首先,
progressBar(), longRunningOperation()您實際上呼叫了長時間運行的操作,因此所有操作都在這里運行。(據我從您不完整的示例中猜測,這只是一個函式呼叫,而不是另一個異步操作)。然后您傳遞結果
operation和progress周圍,??但這些只是unit實際上沒有做任何事情的值。因此,
async { operation }您傳遞給的異步操作onThreadPool根本不執行任何操作。在 中
doBusyAsync,您使用Async.StartImmediate以阻塞方式運行操作(因此這會阻塞執行緒,即使它正在運行某些實際操作)。除了阻塞之外,您也不需要,
async { do! operation }因為這相當于 justoperation。
總之,您的代碼不知何故變得太復雜了。作為第一步,您應該將其簡化為非常基本的內容。我沒有正確的設定來嘗試這個,但我認為以下內容應該可以解決問題:
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)
我洗掉了所有無用的函式和引數傳遞,并盡可能地簡化了它——這只是你長時間運行的操作,async一旦它切換到執行緒池就會直接呼叫。您會得到結果,并且在切換回原始背景關系后,應該能夠在您的用戶界面中顯示該結果。理想情況下,您會使其longRunningOperation本身異步(并使用 呼叫它let!),但上述方法應該可行。
uj5u.com熱心網友回復:
總而言之,我根據 Jim Foye 的評論(關于跳回 UI 執行緒)使用與長時間運行的操作相關的代碼擴展了 Tomá? Pet?í?ek 的代碼。代碼現在就像一個魅力。我要感謝 Tomá? Pet?í?ek 的友好而詳細的回答。
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 <- "Chybny 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 <- "Chybny rozdíl krajních hodnot"
this.ProgressBar2.IsIndeterminate <- false
}
Async.StartImmediate(asyncOperation())//not working with Async.Start
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/365409.html
上一篇:CompletableFuture的complete方法的目的是什么?
下一篇:js承諾等到解決繼續“主要”
