Task.Run( asnyc () => ) Blocking/Not 运行 所有任务 C#

Task.Run( asnyc () => ) Blocking/Not Running All Tasks C#

问题是我尝试 运行 RunPrivateMethod() 多次,但我 运行 遇到阻塞问题,或者当我使用 [=29= 时直接无法工作].与其在这里分享每一次尝试,我只是把我当前的版本。

在 RunPrivateMethod() 中,exeProcess.WaitForExit() 方法是一个外部程序,基本上是 reads/writes/crunches/outputs 数据。我试图 运行 这是一个异步任务,但没有成功。

我不知道这是否合理,但我想限制一次启动的任务数量,所以我在每个案例块的末尾添加了 Task.WaitAll() 。案例 (1) 和案例 (2) 总是都会得到 运行.

所以,这是我的代码。目前,它会在加载每个任务时阻塞。然后似乎只有最后一个任务运行。如果我取出所有任务语句并且 运行 一切正常,它会正常工作。

我真的很感激任何意见或帮助。我的大部分测试最终都会锁定我的系统和键盘。

public void RunSomeTasks(int group)
    {

        switch (group)
        {

            case (1):
                {
                    Task.Run(async () => await RunAsyncMethod(param1, param1, group));
                    Task.Run(async () => await RunAsyncMethod(param1, param2, group));
                    Task.Run(async () => await RunAsyncMethod(param1, param3, group));
                    Task.WaitAll();
                    break;
                }
            case (2):
                {
                    Task.Run(async () => await RunAsyncMethod(param2, param1, group));
                    Task.Run(async () => await RunAsyncMethod(param2, param2, group));
                    Task.Run(async () => await RunAsyncMethod(param2, param3, group));
                    Task.WaitAll();
                    break;
                }
        }
    }

    async Task RunAsyncMethod(string var1, string var2, string varGroup)
    {           

        ////////////////////////////////////////////
        // Use ProcessStartInfo class
        ProcessStartInfo startInfo = new ProcessStartInfo();
        startInfo.CreateNoWindow = false;
        startInfo.UseShellExecute = false;
        startInfo.FileName = "SomeOutsideEXE";
        startInfo.WindowStyle = ProcessWindowStyle.Hidden;
        startInfo.Arguments = var1 + " " + var2 + " " + varGroup;
        using (Process exeProcess = Process.Start(startInfo))
        {
            // did not work -> Task.Run(() => exeProcess.WaitForExit()).Wait();
            exeProcess.WaitForExit();
        }
    }
}

我在这方面工作了无数个小时并阅读了 Cleary 的书,这个最新修订版是这个 post 的一个版本: 目前的结果是每组中的最后一个任务虽然 exeProcess 有效启动时间正确。 运行ning 时我无法使用键盘。

我显然尝试了 RunSomeTasks() 的直接异步方法,然后只是先等待 RunAsyncMethod。我真的需要一些帮助,是的,我已经知道,尽管经过长时间的阅读和反复试验,我也不知道自己到底在做什么。

我稍微修改了您的示例,这应该可以防止 UI 锁定。请注意,我在单击按钮时添加了 async。还使用 WhenAll 并传入启动的任务,而不是使用 WaitAll。 (针对完全异步模式进行了更新)

    private async void button1_Click(object sender, EventArgs e)
    {
        try
        {
            await RunSomeTasks(1);
            await RunSomeTasks(2);
            lblStatus.Text = "done!";
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
    }

    public async Task RunSomeTasks(int group)
    {
        switch (group)
        {
            case (1):
                {
                    var t1 = RunMethodAsync(param1, param1, group);
                    var t2 = RunMethodAsync(param1, param2, group);
                    var t3 = RunMethodAsync(param1, param3, group);
                    await Task.WhenAll(t1, t2, t3).ConfigureAwait(false);
                    break;
                }
            case (2):
                {
                    var t1 = RunMethodAsync(param2, param1, group);
                    var t2 = RunMethodAsync(param2, param2, group);
                    var t3 = RunMethodAsync(param2, param3, group);
                    await Task.WhenAll(t1, t2, t3).ConfigureAwait(false);
                    break;
                }
        }
    }

    async Task RunMethodAsync(string var1, string var2, int varGroup)
    {
        ////////////////////////////////////////////
        // Use ProcessStartInfo class
        ProcessStartInfo startInfo = new ProcessStartInfo();
        startInfo.CreateNoWindow = false;
        startInfo.UseShellExecute = false;
        startInfo.FileName = "SomeOutsideEXE";
        startInfo.WindowStyle = ProcessWindowStyle.Hidden;
        startInfo.Arguments = var1 + " " + var2 + " " + varGroup;

        using (Process exeProcess = new Process())
        {
            var cts = new TaskCompletionSource<int>();

            exeProcess.StartInfo = startInfo;
            exeProcess.EnableRaisingEvents = true;

            exeProcess.Exited += (sender, e) =>
            {
                try
                {
                    cts.SetResult(exeProcess.ExitCode);
                }
                catch (Exception ex)
                {
                    cts.SetException(ex);
                }
            };

            exeProcess.Start();

            await cts.Task.ConfigureAwait(false);
        }
    }

我想出的最干净的方法来做一个 await Process.WaitForExit 是这样的,保存订阅 events

private async Task RunRubyScript(string filePath)
{
  await Task.Run(() =>
  {
    using (var proc = new Process())
    {
      var startInfo = new ProcessStartInfo(@"ruby");
      startInfo.Arguments = filePath;
      startInfo.UseShellExecute = false;
      startInfo.CreateNoWindow = true;
      proc.StartInfo = startInfo;
      proc.Start();
      proc.WaitForExit();
    }
  });
}

这是 运行 一个 ruby 脚本,但很明显 ProcessStartInfo 相应地修改您的内容以满足您的要求。

希望对您有所帮助!