zoukankan      html  css  js  c++  java
  • 设置调用方法的超时时间

    在工作中,遇到这样一个需求,我要做一个业务,要验证一下现有的数据是否正确,但这个验证又不是必须的,只是说如果这里验证不通过,后面流程就可以不走了,但是如果这里没有验证到,后面也会有验证。也就是说不影响主流程,算得上是一个优化吧。比如我要查询一个东西,但是这个时间不能超过1秒。

    在网上查了一下,基本上都是异步执行,有两个线程来做。我查到有两种方法。

    第一种 独立成一个类

    代码如下:

    (1)、FuncTimeOut类

        /// <summary>
        /// 超时设置类
        /// </summary>
        public class FuncTimeOut
        {
            /// <summary>
            /// 信号量
            /// </summary>
            private ManualResetEvent manu = new ManualResetEvent(false);
    
            /// <summary>
            /// 是否接受到信号
            /// </summary>
            private bool isgetSignal;
    
            /// <summary>
            /// 设置超时时间
            /// </summary>
            private int timeout;
    
            /// <summary>
            /// 要委托调用的方法的一个委托
            /// </summary>
            private Action<int> funcNeedRun;
    
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="action">委托</param>
            /// <param name="timeout">超时时间</param>
            public FuncTimeOut(Action<int> action, int timeout)
            {
                this.funcNeedRun = action;
                this.timeout = timeout;
            }
    
            /// <summary>
            /// 执行方法
            /// </summary>
            /// <param name="param">参数</param>
            public void Execute(int param)
            {
                Action<int> tempAction = this.CombineActionAndManuset;
                var r = tempAction.BeginInvoke(param, this.MyAsynCallback, null);
                this.isgetSignal = this.manu.WaitOne(this.timeout);
                if (this.isgetSignal == true)
                {
                    Console.WriteLine("未超时.");
                    Console.WriteLine("ThreadName:" + Thread.CurrentThread.Name);
                }
                else
                {
                    Console.WriteLine("超时");
                    Console.WriteLine("ThreadName:" + Thread.CurrentThread.Name);
                }
            }
    
            /// <summary>
            /// 回调函数
            /// </summary>
            /// <param name="ar">异步操作时的状态</param>
            private void MyAsynCallback(IAsyncResult ar)
            {
                if (this.isgetSignal == false)
                {
                    Console.WriteLine(Thread.CurrentThread.Name + ",超时,放弃执行回调函数");
                    Thread.CurrentThread.Abort();
                }
                else
                {
                    Console.WriteLine(Thread.CurrentThread.Name + ",执行成功");
                }
            }
    
            /// <summary>
            /// 执行方法
            /// </summary>
            /// <param name="para">参数</param>
            private void CombineActionAndManuset(int para)
            {
                Thread.CurrentThread.Name = "subThread";
                this.funcNeedRun(para);
                this.manu.Set();
            }
        }

    (2)、测试代码

        /// <summary>
        /// Class Program
        /// </summary>
        public class Program
        {
            /// <summary>
            /// Defines the entry point of the application.
            /// </summary>
            /// <param name="args">The args.</param>
            public static void Main(string[] args)
            {
                TestFuncTimeOut();
                Console.Read();
            }
    
            #region FunTimeOut测试
    
            /// <summary>
            /// 测试超时设置操作
            /// </summary>
            private static void TestFuncTimeOut()
            {
                Console.WriteLine("start");
                Thread.CurrentThread.Name = "Main";
                FuncTimeOut ft = new FuncTimeOut(ComputeSum, 3000);
                ft.Execute(10); // 测试修改点
                Console.WriteLine("ThreadName:" + Thread.CurrentThread.Name);
                Console.WriteLine("end");
            }
    
            /// <summary>
            /// Does the STH.
            /// </summary>
            /// <param name="num">The num.</param>
            private static void ComputeSum(int num)
            {
                int sum = 0;
                for (int i = 0; i < num; i++)
                {
                    Thread.Sleep(500);
                    sum += i;
                    Console.WriteLine(i + ":ThreadName:" + Thread.CurrentThread.Name);
                }
    
                Console.WriteLine("sum = " + sum);
    
                // return sum;
            }
    
            #endregion
       }

    (3)、执行结果

    a、超时的情况(上面的测试代码测出来的结果)

     1 start
     2 0:ThreadName:subThread
     3 1:ThreadName:subThread
     4 2:ThreadName:subThread
     5 3:ThreadName:subThread
     6 4:ThreadName:subThread
     7 超时
     8 ThreadName:Main
     9 ThreadName:Main
    10 end
    11 5:ThreadName:subThread
    12 6:ThreadName:subThread
    13 7:ThreadName:subThread
    14 8:ThreadName:subThread
    15 9:ThreadName:subThread
    16 sum = 45
    17 subThread,超时,放弃执行回调函数

    b、未超时的情况(将上述黄色部分的标示改为:ft.Execute(3);的结果)

     1 start
     2 0:ThreadName:subThread
     3 1:ThreadName:subThread
     4 2:ThreadName:subThread
     5 sum = 3
     6 未超时.
     7 ThreadName:Main
     8 ThreadName:Main
     9 end
    10 subThread,执行成功

    (4)、总结

    从上面的结果可以看出:

    第一、有两个线程

    第二、无论是否超时,方法都会被执行完毕,如果超时,则不忘下执行回调函数,否则执行。

    第二种 封装成一个方法

    (1)、源代码

            /// <summary>
            /// 连续整数求和【测试方法】
            /// </summary>
            /// <param name="num">个数</param>
            /// <returns>结果</returns>
            private static int ComputeSumResult(int num)
            {
                int sum = 0;
                for (int i = 0; i < num; i++)
                {
                    Thread.Sleep(500);
                    sum += i;
                    Console.WriteLine(i + ",ThreadName:" + Thread.CurrentThread.Name);
                }
    
                return sum;
            }
    
            /// <summary>
            /// 超时方法调用
            /// </summary>
            /// <param name="func">要调用的方法</param>
            /// <param name="param">要调用方法的参数</param>
            /// <param name="timeoutMillisecondes">超时时间</param>
            /// <returns>结束</returns>
            private static int CallWithTimeOutFun(Func<int, int> func, int param, int timeoutMillisecondes)
            {
                Thread threadToKill = null;
                int sum = 0;
                Action wrappedAction = () =>
                {
                    threadToKill = Thread.CurrentThread;
                    threadToKill.Name = "threadToKill";
                    sum = func(param);
                };
                IAsyncResult result = wrappedAction.BeginInvoke(null, null);
                if (result.AsyncWaitHandle.WaitOne(timeoutMillisecondes))
                {
                    Console.WriteLine("ThreadName:" + Thread.CurrentThread.Name);
                    wrappedAction.EndInvoke(result);
                    Console.WriteLine("没有超时");
                    Console.WriteLine("ThreadName:" + Thread.CurrentThread.Name);
                    return sum;
                }
                else
                {
                    Console.WriteLine("ThreadName:" + Thread.CurrentThread.Name);
                    threadToKill.Abort();
                    Console.WriteLine("超时");
                    Console.WriteLine("ThreadName:" + Thread.CurrentThread.Name);
                    return sum;
                }
            }

    (2)、测试代码

        /// <summary>
        /// Class Program
        /// </summary>
        public class Program
        {
            /// <summary>
            /// Defines the entry point of the application.
            /// </summary>
            /// <param name="args">The args.</param>
            public static void Main(string[] args)
            {
                Console.WriteLine("start");
                Thread.CurrentThread.Name = "Main";
                int result = CallWithTimeOutFun(ComputeSumResult, 10, 3000);// 测试需要修改的代码
                Console.WriteLine("ThreadName:" + Thread.CurrentThread.Name + ", 结果是:" + result);
                Console.WriteLine("end");
                Console.Read();
            }
       }

    (3)、测试结果

    a、超时情况

     1 start
     2 0,ThreadName:threadToKill
     3 1,ThreadName:threadToKill
     4 2,ThreadName:threadToKill
     5 3,ThreadName:threadToKill
     6 4,ThreadName:threadToKill
     7 ThreadName:Main
     8 超时
     9 ThreadName:Main
    10 ThreadName:Main, 结果是:0
    11 end

    b、不超时的情况(将上面测试需要修改的代码修改为:int result = CallWithTimeOutFun(ComputeSumResult, 3, 3000);// 测试需要修改的代码)

    1 start
    2 0,ThreadName:threadToKill
    3 1,ThreadName:threadToKill
    4 2,ThreadName:threadToKill
    5 ThreadName:Main
    6 没有超时
    7 ThreadName:Main
    8 ThreadName:Main, 结果是:3
    9 end

    (4)、总结

    从上面的结果可以看出:

    第一、有两个线程

    第二、如果方法超时,则不会将被调用的方法执行完毕,可以看出,方法是执行了,但由于超时,结果是不对的。如果方法没有超时,结果为正确的。这与上面方法的区别在于,方法超时就不会继续执行了。

    作者:BestNow
    出处:http://www.cnblogs.com/BestNow/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    CMU15-445 Project #2
    CMU15-445 Project #1 Buffer Pool
    挂分原因
    「杂谈」关于斜率优化维护凸包
    「题解」GYM 101620J Justified Jungle
    「题解」AGC 052 B Tree Edges XOR
    C++ MT19937 随机数 限制范围
    「题解」Codeforces 348C Subset Sums
    「学习笔记」联赛数论再学习
    「题解」洛谷 P4597 序列sequence
  • 原文地址:https://www.cnblogs.com/tianxue/p/3935783.html
Copyright © 2011-2022 走看看