You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

异步进程结束后执行大规模后置处理的最佳实践及方案验证

异步事件处理器

我写了下面这个类用来异步执行可执行文件:

namespace Feather
{
    internal class Helper
    {
        private static Process cmd;

        public static void RunLogic(string args)
        {
            cmd = new Process();

            cmd.StartInfo.FileName = "Cotton.exe";
            cmd.StartInfo.Arguments = args;
            cmd.EnableRaisingEvents = true;
            cmd.Exited += new EventHandler(cmd_Exited);
        }

        private static void cmd_Exited(object sender, EventArgs e)
        {
            // 进程已结束
            cmd.Dispose();

            // 可执行文件会生成一个输出文件
            // 这个输出文件需要后置处理
            // 后置处理代码量很大
            // TODO: 在这里运行大量后置处理代码的最佳实践是什么?
        }
    }
}
触发逻辑

我在另一个类里触发这个可执行文件的运行,代码如下:

namespace Feather
{
    public class FeatherHollow : Command
    {

        protected override Result RunCommand(RhinoDoc doc, RunMode mode)
        {
            string args = "";

            // 触发可执行文件的异步运行
            Helper.RunLogic(args);

            // TODO: 当可执行文件生成输出文件后,如何运行大量后置处理代码?

            return Result.Success;
        }
    }
}
问题

异步进程结束后,运行大规模后置处理代码的最佳实践和最简方式是什么?

delegate方案

这个方案是不是最佳选择?

namespace Feather
{
    internal class Helper
    {
        public delegate void PostProcess(object sender, EventArgs e);

        public static void RunLogic(string args, PostProcess pp)
        {
                // ...
                cmd.Exited += new EventHandler(cmd_Exited);
                cmd.Exited += new EventHandler(pp);
                // ...
        }
    }
}

调用类的代码如下:

namespace Feather
{
    public class FeatherHollow : Command
    {
        protected override Result RunCommand(RhinoDoc doc, RunMode mode)
        {
            // ...
            Helper.RunLogic(args, PostProcess);
            // ...
        }

        private static void PostProcess(object sender, EventArgs e)
        {
            // 大量后置处理代码写在这里
        }
    }
}

方案分析与优化建议

你提出的delegate方案是可行的,但可以做些优化让代码更贴合.NET的通用写法:

  1. 复用内置委托类型
    没必要自定义PostProcess委托,直接用.NET原生的EventHandler就够了,减少冗余代码:
namespace Feather
{
    internal class Helper
    {
        private static Process cmd;

        public static void RunLogic(string args, EventHandler postProcessHandler)
        {
            cmd = new Process();
            cmd.StartInfo.FileName = "Cotton.exe";
            cmd.StartInfo.Arguments = args;
            cmd.EnableRaisingEvents = true;
            cmd.Exited += cmd_Exited;
            cmd.Exited += postProcessHandler;
            cmd.Start(); // 注意:原代码遗漏了启动进程的关键调用
        }

        private static void cmd_Exited(object sender, EventArgs e)
        {
            cmd.Dispose();
        }
    }
}

调用端的写法和你原来的实现一致,不需要额外改动。

  1. 使用async/await简化异步逻辑
    如果你的项目基于.NET Framework 4.5+或者.NET Core/.NET 5+,更推荐用async/await来实现异步流程,代码线性化,可读性更强:
namespace Feather
{
    internal class Helper
    {
        public static async Task RunLogicAsync(string args)
        {
            using var cmd = new Process();
            cmd.StartInfo.FileName = "Cotton.exe";
            cmd.StartInfo.Arguments = args;
            cmd.StartInfo.UseShellExecute = false; // 必须设置此属性才能使用WaitForExitAsync
            cmd.Start();

            await cmd.WaitForExitAsync();
            // 进程结束后可直接在这里处理,或者交由调用方执行后置逻辑
        }
    }
}

调用类的代码可以改成异步版本:

namespace Feather
{
    public class FeatherHollow : Command
    {
        protected override async Task<Result> RunCommandAsync(RhinoDoc doc, RunMode mode)
        {
            string args = "";
            await Helper.RunLogicAsync(args);
            
            // 直接在这里编写后置处理代码,逻辑更连贯
            ExecutePostProcess();
            
            return Result.Success;
        }

        private void ExecutePostProcess()
        {
            // 大规模后置处理代码
        }
    }
}

这种方式避免了事件订阅的繁琐,异步逻辑一目了然,更符合现代C#异步编程的最佳实践。

  1. 大规模后置处理的注意点
  • 如果后置处理是CPU密集型任务,建议用Task.Run放到后台线程执行,避免阻塞主线程(尤其是UI场景):
    private void ExecutePostProcess()
    {
        Task.Run(() =>
        {
            // 耗时的后置处理操作
        });
    }
    
  • 确保后置处理中的资源访问是线程安全的,比如操作UI控件需要切换回主线程,共享数据要加锁或者使用线程安全容器。

总结

  • 你的delegate方案是合理的事件驱动实现,适合传统异步场景,优化后更简洁。
  • async/await方案更现代,代码可读性和可维护性更强,优先推荐使用。
  • 根据后置处理的类型(CPU密集/IO密集)选择合适的执行线程,保证程序性能和响应性。

内容的提问来源于stack exchange,提问作者Megidd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 22:17:47