设置调用方法的超时时间

在工作中,遇到这样一个需求,我要做一个业务,要验证一下现有的数据是否正确,但这个验证又不是必须的,只是说如果这里验证不通过,后面流程就可以不走了,但是如果这里没有验证到,后面也会有验证。也就是说不影响主流程,算得上是一个优化吧。比如我要查询一个东西,但是这个时间不能超过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/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
原文地址:https://www.cnblogs.com/tianxue/p/3935783.html