C# 设置方法执行超时,则执行下一个方法

发布于:2024-12-06 ⋅ 阅读:(34) ⋅ 点赞:(0)

最近在开发过程中遇到了一个问题,在进行通讯连接时,如果没有连接的话会延时几十秒,而且还设置不了连接超时时间,于是我就想着有没有一种可以判断这个方法的执行时间超过多少秒,就跳出执行其他方法,经过大量搜索,找到了几种方法,基本上都是以循环来判断实现的,也有一种直接设置方法执行时间的,因为我的遇到的问题比较少见,所以用了第三种不常见的方法来实现,大家可以根据自己的需求来选择。

一、异步方法场景(使用 Task 和 CancellationToken)

当处理异步方法时,借助 CancellationToken 来实现超时控制并在超时时执行下一个方法是一种比较常用且规范的做法,示例代码如下:

using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        // 设置超时时间对应的CancellationTokenSource,这里假设超时时间为3秒,可按需调整
        CancellationTokenSource cts = new CancellationTokenSource(3000); 

        try
        {
            await DoFirstAsync(cts.Token);
        }
        catch (OperationCanceledException)
        {
            Console.WriteLine("第一个方法执行超时,开始执行下一个方法");
            await DoNextAsync();
        }

        Console.ReadLine();
    }

    static async Task DoFirstAsync(CancellationToken cancellationToken)
    {
        // 模拟一个耗时的异步操作,比如网络请求、长时间的文件读取等
        // 这里使用Task.Delay来模拟耗时操作,实际中替换为真实业务逻辑
        await Task.Delay(5000, cancellationToken); 
    }

    static async Task DoNextAsync()
    {
        Console.WriteLine("正在执行下一个方法...");
        // 在这里添加下一个方法具体要做的业务逻辑,比如进行其他的数据处理、发起新的请求等
        await Task.CompleteTask;
    }
}

在上述代码中:

  • 设置超时机制:
    首先创建了 CancellationTokenSource 实例,并在构造函数中传入超时时间(以毫秒为单位,这里设置为 3000 毫秒即 3 秒),通过它可以获取 CancellationToken,这个令牌用于在异步操作中传递取消信号。
  • 执行第一个异步方法:
    在 DoFirstAsync 方法中,模拟了一个耗时 5 秒的异步操作(通过 Task.Delay(5000, cancellationToken)),同时传递了 CancellationToken。如果在这个异步操作执行过程中,超时时间到了(也就是 3 秒后),CancellationToken 会触发取消操作,使得 Task.Delay 抛出 OperationCanceledException 异常,进而导致 DoFirstAsync 方法停止执行。
  • 捕获异常并执行下一个方法:
    在 Main 方法中,使用 try-catch 块捕获 OperationCanceledException 异常,一旦捕获到,表示第一个方法执行超时了,此时会输出相应提示信息,并接着执行 DoNextAsync 方法,也就是开始执行下一个方法。

二、同步方法场景(使用 Stopwatch 类)

对于同步方法,可以利用 Stopwatch 类来记录方法执行的时间,通过不断判断是否超时来决定是否结束当前方法执行并转去执行下一个方法,示例如下:


using System;
using System.Diagnostics;

class Program
{
    static void Main()
    {
        DoFirst();
        DoNext();

        Console.ReadLine();
    }

    static void DoFirst()
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();

        while (true)
        {
            // 模拟同步方法中的一些操作,这里简单输出内容,实际中替换为真实业务逻辑
            Console.WriteLine("正在执行第一个方法...");

            if (stopwatch.Elapsed.TotalSeconds >= 3)
            {
                Console.WriteLine("第一个方法执行超时,开始执行下一个方法");
                break;
            }
            System.Threading.Thread.Sleep(500);
        }

        stopwatch.Stop();
    }

    static void DoNext()
    {
        Console.WriteLine("正在执行下一个方法...");
        // 在这里添加下一个方法具体要做的业务逻辑,例如对数据进行处理、计算等操作
        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine($"下一个方法中的操作:{i}");
        }
    }
}

在这个示例中:

  • 使用 Stopwatch 计时:
    在 DoFirst 方法中,先创建并启动 Stopwatch 实例来记录时间,然后进入一个循环模拟方法的执行过程(这里只是简单地输出一些内容,实际应用中替换为真实的业务逻辑操作)。
  • 判断超时并结束当前方法:
    在每次循环中,通过 stopwatch.Elapsed.TotalSeconds >= 3 判断是否已经超过了设定的超时时间(这里假设为 3 秒,可按需调整),如果超过了,就输出提示信息并通过 break 跳出循环,结束 DoFirst 方法的执行。
  • 执行下一个方法:
    当 DoFirst 方法结束后,就会接着执行 DoNext 方法,也就是执行下一个需要执行的方法,在 DoNext 方法中可以添加具体的业务逻辑操作。

三、基于委托和 BeginInvoke/EndInvoke 的方式(较老但仍可用的异步模式)

在早期的 C# 异步编程中,可以使用委托的 BeginInvoke 和 EndInvoke 方法来实现类似的超时控制及后续操作,不过现在基于任务的异步模式更为常用,以下是示例代码供参考:

using System;
using System.Threading;

class Program
{
    static void Main()
    {
        // 创建一个委托,指向要执行的第一个方法
        Action firstAction = DoFirst;

        // 开始异步调用第一个方法,并获取IAsyncResult对象用于后续操作
        IAsyncResult asyncResult = firstAction.BeginInvoke(null, null);

        // 设置超时时间,这里假设为3秒,单位是毫秒
        int timeout = 3000;
        bool completed = asyncResult.AsyncWaitHandle.WaitOne(timeout);

        if (completed)
        {
            // 如果在超时时间内完成,获取结果(这里没有返回值所以不需要接收具体结果)
            firstAction.EndInvoke(asyncResult);
        }
        else
        {
            Console.WriteLine("第一个方法执行超时,开始执行下一个方法");
            DoNext();
        }

        Console.ReadLine();
    }

    static void DoFirst()
    {
        // 模拟操作,这里简单输出一些内容,实际替换为真实业务逻辑
        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine("正在执行第一个方法..." + i);
            Thread.Sleep(500);
        }
    }

    static void DoNext()
    {
        Console.WriteLine("正在执行下一个方法...");
        // 在这里添加下一个方法具体要做的业务逻辑,如数据处理等
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine($"下一个方法中的操作:{i}");
        }
    }
}

在上述代码中:

  • 委托异步调用:
    首先创建一个 Action 类型的委托,指向要执行的第一个方法 DoFirst,然后通过 BeginInvoke 方法发起异步调用,并获取到 IAsyncResult 对象,这个对象用于后续判断异步操作是否完成等操作。
  • 设置超时判断:
    设定了超时时间(这里为 3000 毫秒即 3 秒),通过 asyncResult.AsyncWaitHandle.WaitOne(timeout) 来等待异步操作完成,这个方法会返回一个 bool 值,如果在超时时间内操作完成则返回 true,否则返回 false。
  • 根据超时情况执行相应操作:
    如果返回 true,表示在超时时间内第一个方法执行完成了,此时通过 EndInvoke 方法来结束异步调用(如果方法有返回值的话可以在这里获取返回值);如果返回 false,说明执行超时了,就会输出提示信息并执行 DoNext 方法,也就是执行下一个方法。
    这些不同的实现方式可以满足不同的编程场景需求,你可以根据实际的代码结构、方法的同步或异步特性等来选择合适的方式来实现方法执行超时后执行下一个方法的功能。

小白路漫漫,让我们一起加油!!!


网站公告

今日签到

点亮在社区的每一天
去签到

热门文章