C# 打破多个嵌套函数以提高性能的最佳方法

问题描述 投票:0回答:1

我有一个自动化程序用于控制其他应用程序(例如浏览器或桌面应用程序)。 我创建了一个带有“while”的函数来确定应用程序的当前页面或状态,从而决定要执行的下一个操作。

void OuterMostFunc()
{
    while(!exit)
    {
        //InitSomethings...
        InnerFunc();
        //HandleSomethings...
        Thread.Sleep(milliseconds);
    }
}

void InnerFunc()
{
    if(A_Page_Cond)
        A_Func();
    else if(B_Page_Cond)
        B_Func();
    ...
}

但同时,这些应用程序可能会被手动操作或遇到意外事件而改变页面或状态。 因此,我必须检查很多关键点的状态变化,并突破返回最外层函数重新评估情况。 一个相对优雅的解决方案是利用 Try-Catch 以及自定义 BreakException,允许我从代码中的任何位置返回到最外层函数。 此外,我在最外层重置了所有关键变量,因此我不需要担心中断引起的问题。

void OuterMostFunc()
{
    while(!exit)
    {
        //InitSomethings...
        try
        {
            InnerFunc();
        }
        catch(BreakExcetion ex)
        {}
        //HandleSomethings...
        Thread.Sleep(milliseconds);
    }
}

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

长期以来,这种方法一直有效且可靠。 然而,由于程序的应用上下文需要进行极致的性能优化,Try-Catch带来的性能开销变得难以忽视。 例如,Try-Catch需要数十毫秒的执行时间,对CPU造成了较大的负担。”

如果每个函数都返回bool(或out bool),然后我们在调用每个函数后检查是否返回或执行下一步,确实可以让我们快速返回到最外层函数。 然而,这种方法似乎对代码的可读性造成了灾难,特别是考虑到程序中调用的函数的实际复杂性和多层性质。

c# return try-catch goto
1个回答
0
投票

由于这似乎是同步运行的,因此持续运行的 while 循环本身就会对性能产生不利影响。您可能想切换到异步实现。以下是长时间运行的应用程序(例如 Windows 服务或 Web 服务)通常如何使用 BackgroundService 实现:

public sealed class AppService : BackgroundService
{
    // change the update interval as you like, or read from config
    private static readonly _interval = TimeSpan.FromSeconds(1);
    private readonly ILogger<Worker> _logger;

    public Worker(ILogger<Worker> logger)
    {
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                // use asynchronous check if possible
                // (synchronous might also be fine here)
                if (CheckPageChangedAsync(stoppingToken))
                {
                    // do something
                }
            }
            catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
            {
                // was canceled
            }
            catch (Exception)
            {
                 _logger.LogError(exception, "Unexpected exception occured");
                 // throw or exit gracefully
                 throw;
            }
            // pause to free resources before the next update
            await Task.Delay(_interval, stoppingToken);
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.