使用控制台应用程序 .NET Core 在 C# 中并行运行两个 dotnet 进程 [英] Run two dotnet processes in parallel C# with Console app .NET Core

查看:26
本文介绍了使用控制台应用程序 .NET Core 在 C# 中并行运行两个 dotnet 进程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包含三个控制台的项目.一个控制台会并行打开另外两个进程来做一些工作(独立).

I have a project with three consoles. One console will open in parallel other two processes to do some jobs (independently).

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

All consoles are using dotnet core framework.

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

MultipleConsoleWindows is main application which looks like:

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 类:

and ProcessManager class:

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

我正在尝试同时打开两个控制台来完成自己的工作.

I'm trying to open two consoles in same time which do own job.

如何在 MultipleConsoleWindows 端实现?

推荐答案

无需使用 Task.Run 来启动子进程.而不是使用 WaitForExit(); 阻止直到进程退出,文档建议:

There's no need to use Task.Run to start a child process. Instead of using WaitForExit(); to block until the process exits, the documentation suggests :

为避免阻塞当前线程,请使用 退出 事件.

To avoid blocking the current thread, use the Exited event.

在任务之前,事件是异步执行作业和接收通知的方法之一.这称为基于事件的异步模式.可以使用 TaskCompletionSource 将事件转换为任务.这在 如何:在任务中包装 EAP 模式.

Before tasks, events were one of the methods of executing jobs asynchronously and receiving notifications. This is called the Event-Based Asynchronous Pattern. Events can be converted to Tasks using a TaskCompletionSource. This is described in How to: Wrap EAP Patterns in a Task.

这个例子比它应该的要冗长一些.在这种情况下,convertint Exited 到 Task 很简单:

The example is a bit more verbose than it should. In this case, convertint Exited to a Task is straightforward :

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

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

Multiple processes can be started and awaited this way :

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

TaskCompletionSource.SetResult completes the task returned by the tcs and sets its result, in this case a string. SetException can be used to set the task to the faulted state, raising an exception when awaited. This could be used for example to cancel awaiting if any of the processes returned a non-zero exit code

这篇关于使用控制台应用程序 .NET Core 在 C# 中并行运行两个 dotnet 进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆