[英]Releases UI thread while long method is running using await and async
[英]Can I get UI thread context while using 'async/await'
我想知道在使用 Asyn/await 方法時是否可以獲取 UI 線程上下文。 如果是,如何?
使用 WPF/MVVM 模式編寫的代碼:
long asyncTimeChecker = 0;
int prevSec2 = 0;
/// <summary>
/// Button Click Command
/// </summary>
private void ExeTimerActivate(object o)
{
if (!IsTimerStart)
{
ActivateAsyncTicToc();
TimerState = "Stop";
}
else if (IsTimerStart)
{
ActivateAsyncTicToc();
TimerState = "Start";
}
IsTimerStart = !IsTimerStart;
}
/// <summary>
/// Call Method By Async/Await
/// </summary>
private async void ActivateAsyncTicToc()
{
IsTimerStartAsync = !IsTimerStartAsync;
var task1 = Task.Run(() => AsyncTicToc());
await task1;
}
/// <summary>
/// I tried to UI access by other thread what use Async/Await
/// </summary>
private void AsyncTicToc()
{
while (IsTimerStartAsync)
{
System.Threading.Thread.Sleep(10);
AsyncTimeText = $"{asyncTimeChecker / 1000}.{asyncTimeChecker % 1000}";
asyncTimeChecker += 10;
/// ========================================
/// This Position Get CrossThread Problem
/// ========================================
if (prevSec2 < asyncTimeChecker / 1000)
{
prevSec2++;
if (TimerColor2.Color == Colors.Blue)
TimerColor2.Color = Colors.Red;
else
TimerColor2.Color = Colors.Blue;
}
}
}
我知道我們可以使用 Dispatcher 獲取 UI 線程,但想知道是否可以使用 async/await。
您將async
調用包裝在一個任務中。 這會破壞整個狀態機,並最終不必要地使用線程池線程。
調用和任何延續都會在另一個線程中結束,因此如果不進行編組就無法訪問 UI。
如果您絕對需要使用async
void
,則至少應該這樣做 - 它只是在等待任務,而不是包裝它。
private async void ActivateAsyncTicToc()
{
try
{
IsTimerStartAsync = !IsTimerStartAsync;
await AsyncTicToc();
}
catch (Exception e)
{
// make sure you observe exceptions in async void
}
}
更好的是,讓async
傳播使用async Task
:
private async Task ActivateAsyncTicToc()
{
IsTimerStartAsync = !IsTimerStartAsync;
await AsyncTicToc();
}
無論如何,這看起來很可疑,您可能應該這樣做(省略async
和await
)並將任務傳遞給將要等待的其他人。 這是一個小的性能提升:
private Task ActivateAsyncTicToc()
{
IsTimerStartAsync = !IsTimerStartAsync;
return AsyncTicToc();
}
事實上,這是一個雷區,我會在這里待一整天。
您需要開始閱讀有關async
和await
:
首先,您可以使用await Task.Delay(10)
而不是Thread.Sleep(10)
並將您的AsyncTicToc
方法更改為async Task
而不啟動線程。 這將更改 UI 線程(您等待的上下文)中的控件。
其次,要從其他線程更新 UI,如果不想直接使用調度程序,可以使用它的抽象: SynchronizationContext類。 在此處查看更多信息。
示例: SynchronizationContext.Current.Post(action, actionParameter);
第三,使用視圖模型和綁定更合適。 如果您使用 WPF,它會為您同步線程以進行屬性更改。
雖然可以使用Dispatcher
或SynchronizationContext
從另一個線程“伸出”到 UI 線程,但我強烈建議不要這樣做。 這是因為它使您的邏輯更難測試並且更受其環境約束。 在Dispatcher
的情況下,它與在 WPF 環境中運行緊密相關; SynchronizationContext
更好,但它仍然依賴於在某種環境中運行。
使用這種方法,您的邏輯與 UI 線程之間存在依賴關系,如下所示:
UI 代碼 => 后台線程邏輯 => UI 線程
相反,使用后台線程邏輯中的IProgress<T>
和Progress<T>
將進度報告傳送回其調用方,后者決定如何顯示這些進度報告。 然后你的依賴看起來像這樣:
UI 代碼 => 后台線程邏輯
並且您的后台線程邏輯不依賴於存在的 UI 線程。 這使其更具可重用性和可測試性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.