使用控制台应用程序.NET Core在并行C#中运行两个dotnet进程

时间:2018-11-15 09:21:48

标签: c# .net-core

我有一个带有三个控制台的项目。一个控制台将同时打开另外两个进程,以独立完成某些工作。

所有控制台都使用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();
}

和ProcessManager类:

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();
        }
    }
}

ConsoleNumberOneConsoleNumberTwo看起来很相似

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

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

我正在尝试同时打开两个自己工作的控制台。

如何在MultipleConsoleWindows端实现这一目标?

2 个答案:

答案 0 :(得分:0)

Maebe这可以解决问题

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();
}

答案 1 :(得分:0)

无需使用Task.Run来启动子进程。 documentation suggests并不是使用WaitForExit();来阻塞直到进程退出,而是:

  

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

在执行任务之前,事件是异步执行作业和接收通知的方法之一。这称为Event-Based Asynchronous Pattern。可以使用TaskCompletionSource将事件转换为Tasks。 How to: Wrap EAP Patterns in a Task中对此进行了描述。

该示例比应有的更为冗长。在这种情况下,将Exited转换为Task很简单:

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可用于将任务设置为故障状态,等待时引发异常。例如,这可以用于取消任何进程返回非零退出代码

的等待