代码之家  ›  专栏  ›  技术社区  ›  Snake Eyes

使用Console app.NET Core并行运行两个dotnet进程

  •  2
  • Snake Eyes  · 技术社区  · 7 年前

    所有控制台都使用dotnet核心框架。

    MultipleConsoleWindows 是主应用程序,看起来像:

    static void Main(string[] args)
    {
        Task t1 = new Task(async () => { await ProcessManager.StartAsync("c1"); });
        Task t2 = new Task(async () => { await ProcessManager.StartAsync("c2"); });
    
        // what should do here ?
    
        Console.WriteLine("done");
        Console.Read();
    }
    

    public static class ProcessManager
    {
        const string C1 = @"pathTo\ConsoleNumberOne.dll";
        const string C2 = @"pathTo\ConsoleNumberTwo.dll";
    
        public static async Task<string> StartAsync(string type)
        {
            Console.WriteLine($"Start {type}");
    
            var proc = type.Equals("c1") ? C1 : C2;
            return await Task.Run(() => StartProcess(proc));
        }
    
        static string StartProcess(string proc)
        {
            ProcessStartInfo procStartInfo = new ProcessStartInfo();
            procStartInfo.FileName = "dotnet";
            procStartInfo.Arguments = $"\"{proc}\"";
            procStartInfo.WorkingDirectory = Path.GetDirectoryName(proc);
    
            procStartInfo.UseShellExecute = false;
            procStartInfo.CreateNoWindow = true;
    
            procStartInfo.RedirectStandardOutput = true;
            procStartInfo.RedirectStandardError = true;
    
            int output = 0;
    
            StringBuilder sb = new StringBuilder();
            using (Process pr = new Process())
            {
                pr.StartInfo = procStartInfo;
    
                pr.OutputDataReceived += (s, ev) =>
                {
                    if (string.IsNullOrWhiteSpace(ev.Data))
                    {
                        return;
                    }
    
                    sb.AppendLine(ev.Data);
    
                    string[] split = ev.Data.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    int.TryParse(split[split.Length - 1], out output);
                };
    
                pr.ErrorDataReceived += (s, err) =>
                {
                    if (!string.IsNullOrWhiteSpace(err.Data))
                    {
                        sb.AppendLine(err.Data);
    
                        output = 0;
                    }
                };
    
                pr.EnableRaisingEvents = true;
                pr.Start();
                pr.BeginOutputReadLine();
                pr.BeginErrorReadLine();
    
                pr.WaitForExit();
    
                return sb.ToString();
            }
        }
    }
    

    这个 ConsoleNumberOne 和 ConsoleNumberTwo 相像

    static void Main(string[] args)
    {
        Console.WriteLine("Hello World!");
        Thread.Sleep(10000);
    }
    

    static void Main(string[] args)
    {
         Console.WriteLine("Hello World!");
         Thread.Sleep(5000);
    }
    

    如何实现这一目标 多个太阳窗

    2 回复  |  直到 7 年前
        1
  •  1
  •   Panagiotis Kanavos    7 年前

    没有必要使用 Task.Run WaitForExit(); 要在进程退出之前阻止,请 documentation suggests :

    要避免阻塞当前线程,请使用 Exited 事件

    Event-Based Asynchronous Pattern How to: Wrap EAP Patterns in a Task .

    这个例子比它应该的要详细一点。在本例中,convertint Exited 完成一项任务很简单:

    static Task<string> StartProcess(string proc)
    {
    
            StringBuilder sb = new StringBuilder();
            Process pr = new Process
            {
                StartInfo = procStartInfo
            };
    
            var tcs = new TaskCompletionSource<string>();
    
            pr.Exited += (o, e) =>
            {
                tcs.SetResult(sb.ToString());
                pr.Dispose();
            };
    
            ....
    
            return tcs.Task;
    }
    

    可以通过以下方式启动和等待多个进程:

    static async Task Main(string[] args)
    {
        var p1 = StartProcess("--version");
        var p2 = StartProcess("--list-runtimes");
    
        string[] responses=await Task.WhenAll(p1, p2);
    
        ...
    }
    

    TaskCompletionSource.SetResult 完成tcs返回的任务并设置其结果,在本例中为字符串。 SetException 可用于将任务设置为故障状态,在等待时引发异常。例如,如果任何进程返回非零退出代码,则可以使用此选项取消等待

        2
  •  0
  •   CrazyProg    7 年前

    梅贝,这可以达到目的

    static void Main(string[] args)
    {
        Action t1 = new Action(async () => { await ProcessManager.StartAsync("c1"); });
        Action t2 = new Action(async () => { await ProcessManager.StartAsync("c2"); });
        Parallel.Invoke(t1, t2);
    
        Console.WriteLine("done");
        Console.Read();
    }