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

C#高性能跳出多层嵌套函数的最优方案探讨

自动化程序状态中断方案对比与优化建议

背景概述

我开发了一款C#自动化程序,用于控制浏览器、桌面应用等外部程序。程序核心逻辑通过外层循环轮询应用最新状态,判断是否需要执行对应操作,基础结构如下:

void OuterMostFunc()
{
    while(!exit)
    {
        InquiryLatestOuterAppInfo();
        if(<NeedPerform>)
        {
            //InitSomethings...
            DirectingFunc();
            //HandleSomethings...
        }
        Thread.Sleep(milliseconds);
    }
}

void DirectingFunc()
{
    if(A_Page_Cond)
        A_Page_Func();
    else if(B_Page_Cond)
        B_Page_Func();
    ...
}

但外部应用可能被手动操作或遭遇意外导致状态变更,必须在多个关键点检查状态,一旦变更就跳出到最外层重新评估。

原有方案1:自定义异常+Try-Catch中断

此前采用的方案是通过自定义BreakException结合Try-Catch实现任意层级快速中断到最外层,代码如下:

void OuterMostFunc()
{
    while(!exit)
    {
        InquiryLatestOuterAppInfo();
        if(<NeedPerform>)
        {
            //InitSomethings...
            try
            {
                DirectingFunc();
            }
            catch(BreakExcetion ex)
            {}
            //HandleSomethings...
        }
        Thread.Sleep(milliseconds);
    }
}

void Any_Deep_Level_Func()
{
    //DoSomethings.
    if(CheckPageIsChanged())
        throw new BreakException();
    //DoSomethings.
}

该方案优势是逻辑优雅,可从任意深层函数直接跳回最外层,且外层能统一重置变量;但Try-Catch带来的数十毫秒级性能开销和高CPU负载,已无法满足当前场景对速度的极高要求。

原有方案2:返回值检查中断

若改为让每个函数返回bool(或使用out bool),调用后检查是否需要中断,虽能规避性能问题,但会导致代码可读性严重下降——尤其是程序实际函数层级多、逻辑复杂的情况下,每调用一个函数都要加判断,代码冗余度极高。

待评估方案:CancellationTokenSource分层检查

现在考虑传递CancellationTokenSource给所有非单元操作函数,内层检查到状态变更时取消令牌,上层函数调用后检查令牌状态决定是否返回,代码如下:

void OuterMostFunc()
{
    while (!exit)
    {
        InquiryLatestOuterAppInfo();
        if(<NeedPerform>)
        {
            //InitSomethings...
            CancellationTokenSource cts = new CancellationTokenSource();
            DirectingFunc(cts);
            //HandleSomethings...
        }
    }
}

void DirectingFunc(CancellationTokenSource cts)
{
    if(A_Page_Cond)
        A_Page_Func(cts);
    else if(B_Page_Cond)
        B_Page_Func(cts);
}

void A_Page_Func(CancellationTokenSource cts)
{
    //DoSomethings.
    XX_Func(cts);
    if (cts.IsCancellationRequested)
        return;
    //DoSomethings.
}

void XX_Func(CancellationTokenSource cts)
{
    //DoSomethings.
    YY_Func(cts);
    if (cts.IsCancellationRequested)
        return;
    //DoSomethings.
}

void YY_Func(CancellationTokenSource cts)
{
    //DoSomethings.
    if (CheckPageIsChanged())
    {
        cts.Cancel();
        return;
    }
    //DoSomethings.
}

方案评估

这个方案确实比返回值检查方案更简洁,同时解决了异常方案的性能问题,适配当前场景需求:

  • 性能优势:完全规避Try-Catch的开销,符合“状态变更后执行速度优先”的优先级要求
  • 可读性优势:相比返回值方案,不需要每个函数都返回状态标识,仅需传递令牌并在关键调用后检查,代码冗余度大幅降低
  • 控制权符合要求:内层函数可自主检查状态并发起取消,避免外层干预引发的操作冲突

唯一的小缺点是所有相关函数都需要添加CancellationTokenSource参数,会增加函数签名的复杂度,但相比返回值方案的大量重复判断,这种复杂度的提升是可接受的。

如果想进一步优化,可以考虑传递CancellationToken而非CancellationTokenSource给不需要主动取消的函数,仅让需要发起取消的内层函数持有CancellationTokenSource,这样能避免上层函数误操作取消令牌,提升代码安全性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 07:27:06