zoukankan      html  css  js  c++  java
  • C# 给某个方法设定执行超时时间 C#如何控制方法的执行时间,超时则强制退出方法执行 C#函数运行超时则终止执行(任意参数类型及参数个数通用版)

    我自己写的

            /// <summary>
            /// 函数运行超时则终止执行(超时则返回true,否则返回false)
            /// </summary>
            /// <typeparam name="T">参数类型</typeparam>
            /// <param name="action">要被执行的函数</param>
            /// <param name="p">函数需要的一个参数</param>
            /// <param name="timeoutMilliseconds">超时时间(毫秒)</param>
            /// <returns>超时则返回true,否则返回false</returns>
            void CallWithTimeout<T>(Action<T> action, T p, int timeoutMilliseconds)
            {
                Thread threadToKill = null;
                Action wrappedAction = () =>
                {
                    threadToKill = Thread.CurrentThread;
                    action(p);
                };
    
                IAsyncResult result = wrappedAction.BeginInvoke(null, null);
                if (result.AsyncWaitHandle.WaitOne(timeoutMilliseconds))
                {
                    wrappedAction.EndInvoke(result);
                }
                else
                {
                    threadToKill.Abort();
                    throw new TimeoutException();
                }
            }
    
    
    //例子: CallWithTimeout<paramDj>(myFun,new paramDj() { dr = dr, kjh = kjh, maxQi = maxQi, minQi = minQi },2000);

    网络上参考的

    在某些情况下(例如通过网络访问数据),常常不希望程序卡住而占用太多时间以至于造成界面假死。

    在这时、我们可以通过Thread、Thread + Invoke(UI)或者是 delegate.BeginInvoke 来避免界面假死,

    但是这样做时,某些代码或者是某个方法的执行超时的时间还是无法操控的。
    那么我们又是否有一种比较通用的方法、来设定某一个方法的执行超时的时间,让该其一旦超过指定时间则跳出指定方法、进而继续向下执行呢?

    答案当然是肯定的。

    delegate.BeginInvoke可以实现代码代码的异步执行,在这种情况下,只要让程序可以等待一个Timespan,如果在Timespan到达之前方法内的代码还没有执行完毕、说明该方法执行超时了。

    那么关键的就是“等待一个Timespan”,而恰好.NET 里提供了一些类和方法来实现该功能。我这里选用的是ManualResetEvent.WaitOne(timespan, false);其返回值代码其是否在特定时间内收到信号,而我们恰好可以利用这个布尔值 外加一个标记变量 来判断一个方法是否执行超时。

    相关的实现代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    
    namespace Common
    {
        public delegate void DoHandler();
    
        public class Timeout
        {
            private ManualResetEvent mTimeoutObject;
            //标记变量
            private bool mBoTimeout;
    
            public DoHandler Do;
    
            public Timeout()
            {
                //  初始状态为 停止
                this.mTimeoutObject = new ManualResetEvent(true);
            }
            ///<summary>
            /// 指定超时时间 异步执行某个方法
            ///</summary>
            ///<returns>执行 是否超时</returns>
            public bool DoWithTimeout(TimeSpan timeSpan)
            {
                if (this.Do == null)
                {
                    return false;
                }
                this.mTimeoutObject.Reset();
                this.mBoTimeout = true; //标记
                this.Do.BeginInvoke(DoAsyncCallBack, null);
                // 等待 信号Set
                if (!this.mTimeoutObject.WaitOne(timeSpan, false))
                {
                    this.mBoTimeout = true;
                }
                return this.mBoTimeout;
            }
            ///<summary>
            /// 异步委托 回调函数
            ///</summary>
            ///<param name="result"></param>
            private void DoAsyncCallBack(IAsyncResult result)
            {
                try
                {
                    this.Do.EndInvoke(result);
                    // 指示方法的执行未超时
                    this.mBoTimeout = false;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    this.mBoTimeout = true;
                }
                finally
                {
                    this.mTimeoutObject.Set();
                }
            }
        }
    }

    测试代码如下:

    class Program
        {
            privatestatic Stopwatch watch;
            privatestatic System.Threading.Timer timer;
    
            [STAThread]
            staticvoid Main(string[] args)
            {
                watch =new Stopwatch();
                Timeout timeout =new Timeout();
                timeout.Do =new Program().DoSomething;
                watch.Start();
                timer =new System.Threading.Timer(timerCallBack, null, 0, 500);
                Console.WriteLine("4秒超时开始执行");
                bool bo = timeout.DoWithTimeout(new TimeSpan(0, 0, 0, 4));
                Console.WriteLine(string.Format("4秒超时执行结果,是否超时:{0}", bo));
                Console.WriteLine("***************************************************");
                
                timeout =new Timeout();
                timeout.Do =new Program().DoSomething;
                Console.WriteLine("6秒超时开始执行");
                bo = timeout.DoWithTimeout(new TimeSpan(0, 0, 0, 6));
                Console.WriteLine(string.Format("6秒超时执行结果,是否超时:{0}", bo));
               
                timerCallBack(null);
               
                watch.Stop();
                timer.Dispose();
                Console.ReadLine();
            }
            staticvoid timerCallBack(object obj)
            {
                Console.WriteLine(string.Format("运行时间:{0}秒", watch.Elapsed.TotalSeconds.ToString("F2")));
            }
            publicvoid DoSomething()
            {
                // 休眠 5秒
                System.Threading.Thread.Sleep(new TimeSpan(0, 0, 0, 5));
            }
        }

    测试代码执行结果如下:

    由上可得知:设定超时时间为4秒执行方法 DoSomething,执行结果为超时,并且在4秒后跳出方法DoSomething继续向下执行。

    C#函数运行超时则终止执行(任意参数类型及参数个数通用版)

    /// <summary>
    /// 控制函数执行时间,超时返回null不继续执行
    /// 调用方法
    /// FuncTimeout.EventNeedRun action = delegate(object[] param)
    /// {
    ///     //调用自定义函数
    ///     return Test(param[0].ToString(), param[1].ToString(), (DateTime)param[2]);
    /// };
    /// FuncTimeout ft = new FuncTimeout(action, 2000);
    /// var result = ft.doAction("1", "2", DateTime.Now);
    /// </summary>
    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="ar"></param>
        public void MyAsyncCallback(IAsyncResult ar)
        {
            //isGetSignal为false,表示异步方法其实已经超出设置的时间,此时不再需要执行回调方法。
            if (isGetSignal == false)
            {
                //放弃执行回调函数;
                Thread.CurrentThread.Abort();
            }
        }
     
        /// <summary>
        /// 调用函数
        /// </summary>
        /// <param name="input">可选个数的输入参数</param>
        /// <returns></returns>
        public object doAction(params object[] input)
        {
            EventNeedRun WhatTodo = CombineActionAndManuset;
            //通过BeginInvoke方法,在线程池上异步的执行方法。
            var r = WhatTodo.BeginInvoke(input, MyAsyncCallback, null);
            //设置阻塞,如果上述的BeginInvoke方法在timeout之前运行完毕,则manu会收到信号。此时isGetSignal为true。
            //如果timeout时间内,还未收到信号,即异步方法还未运行完毕,则isGetSignal为false。
            isGetSignal = manu.WaitOne(timeout);
     
            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)
        {
            var output = FunctionNeedRun(input);
            manu.Set();
            return output;
        }
    }

    C#如何控制方法的执行时间,超时则强制退出方法执行 (这个比较有用)

    class Program
    {
    
        static void Main(string[] args)
        {
            //try the five second method with a 6 second timeout
            CallWithTimeout(FiveSecondMethod, 6000);
    
            //try the five second method with a 4 second timeout
            //this will throw a timeout exception
            CallWithTimeout(FiveSecondMethod, 4000);
        }
    
        static void FiveSecondMethod()
        {
            Thread.Sleep(5000);
        }
        static void CallWithTimeout(Action action, int timeoutMilliseconds)
        {
            Thread threadToKill = null;
            Action wrappedAction = () =>
            {
                threadToKill = Thread.CurrentThread;
                action();
            };
    
            IAsyncResult result = wrappedAction.BeginInvoke(null, null);
            if (result.AsyncWaitHandle.WaitOne(timeoutMilliseconds))
            {
                wrappedAction.EndInvoke(result);
            }
            else
            {
                threadToKill.Abort();
                throw new TimeoutException();
            }
        }
    
    }
  • 相关阅读:
    智能推荐算法演变及学习笔记(三):CTR预估模型综述
    从中国农业银行“雅典娜杯”数据挖掘大赛看金融行业数据分析与建模方法
    智能推荐算法演变及学习笔记(二):基于图模型的智能推荐(含知识图谱/图神经网络)
    (设计模式专题3)模板方法模式
    (设计模式专题2)策略模式
    (设计模式专题1)为什么要使用设计模式?
    关于macOS上常用操作命令(持续更新)
    记录下关于RabbitMQ常用知识点(持续更新)
    EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.
    SpringCloud教程二:Ribbon(Finchley版)
  • 原文地址:https://www.cnblogs.com/chengulv/p/4779672.html
Copyright © 2011-2022 走看看