• 给方法添加超时时间


    有些方法在使用时可以会花费较多的时间,严重影响用户体验。现在给方法添加超时时间,时间一过就主动放弃。

    public void CallWithTimeout(Action action, int timeoutMilliseconds)
    {
        Thread thread = null;
        Action wrappedAction = () =>
        {
            thread = Thread.CurrentThread;
            action();
        };
    
        IAsyncResult result = wrappedAction.BeginInvoke(null, null);
        if (result.AsyncWaitHandle.WaitOne(timeoutMilliseconds))    //在指定时间内是否收到信号
        {
            wrappedAction.EndInvoke(result);
        }
        else
        {
            thread.Abort();
        }
    }
    public void TestProcdure()
    {
        Thread.Sleep(5000);     //这个方法要5秒的执行时间
    }

    测试代码:

    CallWithTimeout(TestProcdure, 4000);    //执行时间为4秒,方法中止
    CallWithTimeout(TestProcdure, 6000);    //执行时间为6秒,方法正常执行

    上面的方法有一个缺点,我们不知道执行成功或是中止,因为方法都没有返回值。可以针对上面的方法做一些小的调整

    private string CallWithTimeout(Func<string> func, int timeoutMilliseconds)    //把Action改成Func类型
    {
        Thread thread = null;
        Func<string> wrappedFunc = () =>
        {
            thread = Thread.CurrentThread;
            return func();
        };
    
        IAsyncResult result = wrappedFunc.BeginInvoke(null, null);
        if (result.AsyncWaitHandle.WaitOne(timeoutMilliseconds))
        {
            return wrappedFunc.EndInvoke(result);    //方法成功执行返回值
        }
        else
        {
            thread.Abort();
            return string.Empty;    //方法中止返回值
        }
    }
    public string TestProcdure()
    {
        Thread.Sleep(5000);     //这个方法要5秒的执行时间
        return "SUCCESS";
    }

    测试代码:

    string result = CallWithTimeout(TestProcdure, 4000);    //执行时间为4秒,方法中止   result = string.Empty
    result = CallWithTimeout(TestProcdure, 6000);    //执行时间为6秒,方法正常执行  result = "SUCCESS"

    注意,Func仅支持4.0以上的版本,要在2.0下使用可以用下面的类。

    任意参数类型及参数个数通用版(2.0下亲测成功)

    public class FuncTimeout
    {
        /// <summary>
        /// 信号量
        /// </summary>
        public ManualResetEvent manu = new ManualResetEvent(false);
        /// <summary>
        /// 是否接受到信号
        /// </summary>
        public bool isGetSignal;
        /// <summary>
        /// 设置超时时间
        /// </summary>
        public int timeout;
        /// <summary>
        /// 定义一个委托 ,输入参数可选,输出object
        /// </summary>
        public delegate object EventNeedRun(params object[] param);
        /// <summary>  
        /// 要调用的方法的一个委托  
        /// </summary>  
        private EventNeedRun FunctionNeedRun;
    
        /// <summary>
        /// 构造函数,传入超时的时间以及运行的方法
        /// </summary>
        /// <param name="_action">运行的方法 </param>
        /// <param name="_timeout">超时的时间</param>
        public FuncTimeout(EventNeedRun _action, int _timeout)
        {
            FunctionNeedRun = _action;
            timeout = _timeout;
        }
    
        /// <summary>
        /// 调用函数
        /// </summary>
        /// <param name="input">可选个数的输入参数</param>
        /// <returns></returns>
        public object doAction(params object[] input)
        {
            EventNeedRun WhatTodo = CombineActionAndManuset;
            //通过BeginInvoke方法,在线程池上异步的执行方法。
            IAsyncResult r = WhatTodo.BeginInvoke(input, MyAsyncCallback, null);
            //设置阻塞,如果上述的BeginInvoke方法在timeout之前运行完毕,则manu会收到信号。此时isGetSignal为true。
            //如果timeout时间内,还未收到信号,即异步方法还未运行完毕,则isGetSignal为false。
            isGetSignal = manu.WaitOne(timeout, false);   //WaitOne方法在Framework2.0下不支持一个参数的,这里要给两个参数才能兼容2.0的版本。
    
            if (isGetSignal == true)
            {
                return WhatTodo.EndInvoke(r);
            }
            else
            {
                return null;
            }
        }
    
        /// <summary>
        /// 把要传进来的方法,和 manu.Set()的方法合并到一个方法体。
        /// action方法运行完毕后,设置信号量,以取消阻塞。
        /// </summary>
        /// <param name="input">输入参数</param>
        /// <returns></returns>
        public object CombineActionAndManuset(params object[] input)
        {
            object output = FunctionNeedRun(input);
            manu.Set();
            return output;
        }
    
        /// <summary>
        /// 回调函数
        /// </summary>
        /// <param name="ar"></param>
        public void MyAsyncCallback(IAsyncResult ar)
        {
            //isGetSignal为false,表示异步方法其实已经超出设置的时间,此时不再需要执行回调方法。
            if (isGetSignal == false)
            {
                //放弃执行回调函数;
                Thread.CurrentThread.Abort();
            }
        }
    }
    public object TestProcdure(params object[] param)
    {
        Thread.Sleep(5000);     //这个方法要5秒的执行时间
        return "SUCCESS";
    }

    测试代码:

    FuncTimeout.EventNeedRun action = new FuncTimeout.EventNeedRun(TestProcdure);
    FuncTimeout ft = new FuncTimeout(action, 4000);
    string result = (string)ft.doAction();    //执行时间为4秒,方法中止   result = string.Empty
    ft = new FuncTimeout(action, 6000);
    result = (string)ft.doAction();    //执行时间为6秒,方法正常执行  result = "SUCCESS"

    可以看出来,上面的TestProcdure有些奇怪,返回值为什么用object,为什么有参数。

    其实这个测试方法只是为了和FuncTimeout类里面的委托一致,具体使用时可以做相应的调整。

  • 相关阅读:
    apche启动错误|httpd.pid overwritten — Unclean shutdown of previous Apache run?
    查看Mysql版本号 (最简单的是status )
    在不损坏C盘的情况下为C盘扩容,适用于Win
    Python环境配置安装
    用Python建立最简单的web服务器
    MongoDB
    MongoDB
    MongoDB
    MongoDB
    MongoDB
  • 原文地址:https://www.cnblogs.com/TanSea/p/Method-Add-Timeout.html
Copyright © 2020-2023  润新知