[英]How does running several tasks asynchronously on UI thread using async/await work?
[英]WPF async await Task Locks UI Thread Running Tasks in Parallel
我有一個WPF應用程序,按下按鈕后,創建一個List<Task<int>>
並啟動這些任務。 我的假設是Add()
調用並行啟動它們,但異步啟動。
這是我在遠程機器上串行執行大量WMI調用的函數:
AgentBootstrapper.cs
public async Task<int> BootstrapAsync(BootstrapContext context, IProgress<BootstrapAsyncProgress> progress)
{
...
do a bunch of stuff in serial *without* await calls
...
if (progress != null)
{
progress.Report(new BootstrapAsyncProgress
{
MachineName = context.MachineName,
ProgressPercentage = 30,
Text = "Copying install agent software to \\\\" + context.MachineName + "\\" + context.ShareName
});
}
...
return pid; // ProcessId of the remote agent that was just started
}
這顯然是UI中的按鈕處理程序:
Shell.xaml.cs
private async void InstallButton_Click(object sender, RoutedEventArgs e)
{
var bootstrapTasks = new List<Task<int>>();
var progress = new Progress<BootstrapAsyncProgress>();
progress.ProgressChanged += (o, asyncProgress) =>
{
Debug.WriteLine("{0}: {1}% {2}", asyncProgress.MachineName, asyncProgress.ProgressPercentage,
asyncProgress.Text);
//TODO Update ViewModel property for ProgressPercentage
};
var vm = DataContext as ShellViewModel;
Debug.Assert(vm != null);
foreach (var targetMachine in vm.TargetMachines)
{
var bootstrapContext = new BootstrapContext(targetMachine.MachineName, true)
{
AdminUser = vm.AdminUser,
AdminPassword = vm.AdminPassword
};
var bootstrapper = new AgentBootstrapper(bootstrapContext);
bootstrapTasks.Add(bootstrapper.BootstrapAsync(bootstrapContext, progress)); // UI thread locks up here
}
}
我知道標記為async
函數應該使用await
在其中進行函數調用。 在我的例子中,這些都是對一些同步WMi輔助函數的調用,這些函數都返回void
。 所以,我不認為await
是我想要的。
簡單地說,我想要所有bootstrapTasks
項目(對bootstrapper.BootstrapAsync()
的調用立即觸發,並讓UI線程從所有這些項目接收進度事件。當整個批次完成后,我將需要處理太。
更新1
嘗試使用Task.Run()
修復了UI鎖定問題,但只執行了第一個Task實例。 更新foreach循環:
foreach (var targetMachine in vm.TargetMachines)
{
var tm = targetMachine; // copy closure variable
var bootstrapContext = new BootstrapContext(tm.MachineName, true)
{
AdminUser = vm.AdminUser,
AdminPassword = vm.AdminPassword
};
var bootstrapper = new AgentBootstrapper(bootstrapContext);
Debug.WriteLine("Starting Bootstrap task on default thread pool...");
var task = Task.Run(() =>
{
var pid = bootstrapper.Bootstrap(bootstrapContext, progress);
return pid;
});
Debug.WriteLine("Adding Task<int> " + task.Id + " to List<Task<int>>.");
tasks.Add(task);
await Task.WhenAll(tasks); // Don't proceed with the rest of this function untill all tasks are complete
}
更新2
移動await Task.WhenAll(tasks);
foreach
循環外部允許所有任務並行運行。
為async
/ await
生成的代碼中沒有任何內容涉及線程的創建。 使用async
關鍵字不會導致使用另一個線程。 所有async
都允許您使用await
關鍵字。 如果您希望在另一個線程上發生某些事情,請嘗試使用Task.Run
。
在線程池中運行任務(使用默認任務調度程序,即)並在UI線程中await Task.WhenAll(bootstrapTasks)
?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.