给方法添加超时时间

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

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类里面的委托一致,具体使用时可以做相应的调整。

转载于:https://www.cnblogs.com/TanSea/p/Method-Add-Timeout.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值