Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WPF异步等待任务锁定并行运行任务的UI线程_C#_Wpf_Multithreading_Asynchronous_Task Parallel Library - Fatal编程技术网

C# WPF异步等待任务锁定并行运行任务的UI线程

C# WPF异步等待任务锁定并行运行任务的UI线程,c#,wpf,multithreading,asynchronous,task-parallel-library,C#,Wpf,Multithreading,Asynchronous,Task Parallel Library,我有一个WPF应用程序,它在点击按钮时创建一个列表,并启动这些任务。我的假设是,Add()调用以并行但异步的方式启动它们 这是我的函数,它在远程计算机上串行执行一系列WMI调用: AgentBootstrapper.cs public async Task<int> BootstrapAsync(BootstrapContext context, IProgress<BootstrapAsyncProgress> progress) { ... do a bun

我有一个WPF应用程序,它在点击按钮时创建一个
列表
,并启动这些任务。我的假设是,
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
}
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
    }
}
更新2


移动
等待任务WhenAll(任务)foreach
循环之外的code>允许所有任务并行运行。

在线程池上运行任务(即使用默认的任务调度程序)和
等待任务。whalll(bootstrapTasks)
在UI线程中的线程上?

async
/
wait
生成的代码中没有任何内容涉及线程的创建。使用
async
关键字不会导致使用另一个线程。
async
只允许您使用
wait
关键字。如果您希望在另一个线程上发生某些事情,请尝试使用
Task.Run

,因为
Task.WaitAll()返回void,所以该线程不会编译。遗憾的是,这没有任何效果。它永远不会到达这条线。它被锁定在foreach循环中,执行Add()。不要只调用Bootstrap.Async-它会阻止,而是将其作为任务运行。如果您继续编辑答案,这些注释将毫无意义。我并不特别关心它是否位于不同的线程上。我就是不能锁定主线程。@MarkRichman我的观点是,如果你进行阻塞调用,它就是在UI线程上阻塞,因为你从未将任何东西移出该线程。您需要将所有串行阻塞代码放入一个操作中,并使用
任务调用它。运行
。谢谢,我认为这样做了。我将
Add()
调用替换为这一行
wait Task.Run(()=>bootstrapper.bootstrappasync(bootstrapContext,progress))。用户界面没有锁定。那么,在这一点上,
BootstrapAsync
甚至需要是一个异步方法吗?此外,这些进度事件将如何返回到其位于UI线程上的事件处理程序?@MarkRichman如果您从不等待,则它不需要是
async
。进度事件将在UI线程上引发,因为
progress
类捕获创建它的线程的
SynchronizationContext
。它类似于
BackgroundWorker
处理
ReportProgress
的方式。在foreach循环中的
int-pid=wait Task.Run(()=>bootstrapper.Bootstrap(bootstrapContext,progress))中的第一次迭代之后,它看起来仍然在阻塞我将进度消息返回给处理程序,但其他任务不能并行运行。我必须这样做。我使用任务完成源并使用linq轮询列表。进度报告是通过每个任务附带的同步上下文完成的。@GarryVass我刚刚用更多信息更新了我的问题。您的方法仍然适用吗?@MarkRichman,仅供参考:@Noseratio可以,但是如果您
等待任务。Run()
如何处理等待的任务?我需要将任务添加到我的
列表中
。愚蠢的我-我只需要移动
等待任务。whalll(任务)在我的循环之外。作品
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
}