加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 异步延迟超时任务

发布时间:2020-12-15 17:23:29 所属栏目:百科 来源:网络整理
导读:我有一个异步操作依赖于另一个服务器,它需要大部分随机的时间来完成.当异步操作正在运行时,“主线程”中也会进行处理,这也需要一段随机的时间来完成. 主线程启动异步任务,执行它的主要任务,并在最后检查异步任务的结果. 异步线程提取数据并计算对主线程不完
我有一个异步操作依赖于另一个服务器,它需要大部分随机的时间来完成.当异步操作正在运行时,“主线程”中也会进行处理,这也需要一段随机的时间来完成.

主线程启动异步任务,执行它的主要任务,并在最后检查异步任务的结果.

异步线程提取数据并计算对主线程不完整的字段.但是,如果计算能够在不减慢主线程的情况下完成,那么这些数据会很好(并且应该包括在内).

I’d like to setup the async task to run at minimum for 2 seconds,but
to take all the time available between start and end of the main task.
It’s a ‘lazy timeout’ in that it only timeouts if exceeded the 2
second runtime and the result is actually being requested. (The async
task should take the greater of 2 seconds,or the total runtime of the
main task)

编辑(试图澄清要求):如果异步任务有机会运行2秒,它根本不应该阻塞主线程.主线程必须允许异步任务运行至少2秒.此外,如果主线程完成时间超过2秒,则应允许异步任务与主线程一样长时间运行.

我设计了一个有效的包装器,但是我更喜欢一个实际上是Task类型的解决方案.请参阅下面的包装解决方案.

public class LazyTimeoutTaskWrapper<tResult>
{
    private int _timeout;
    private DateTime _startTime;
    private Task<tResult> _task;
    private IEnumerable<Action> _timeoutActions;

    public LazyTimeoutTaskWrapper(Task<tResult> theTask,int timeoutInMillis,System.DateTime whenStarted,IEnumerable<Action> onTimeouts)
    {
        this._task = theTask;
        this._timeout = timeoutInMillis;
        this._startTime = whenStarted;
        this._timeoutActions = onTimeouts;
    }

    private void onTimeout()
    {
        foreach (var timeoutAction in _timeoutActions)
        {
            timeoutAction();
        }
    }

    public tResult Result
    {
        get
        {
            var dif = this._timeout - (int)System.DateTime.Now.Subtract(this._startTime).TotalMilliseconds;
            if (_task.IsCompleted ||
                (dif > 0 && _task.Wait(dif)))
            {
                return _task.Result;
            }
            else
            {
                onTimeout();
                throw new TimeoutException("Timeout Waiting For Task To Complete");
            }
        }
    }

    public LazyTimeoutTaskWrapper<tNewResult> ContinueWith<tNewResult>(Func<Task<tResult>,tNewResult> continuation,params Action[] onTimeouts)
    {
        var result = new LazyTimeoutTaskWrapper<tNewResult>(this._task.ContinueWith(continuation),this._timeout,this._startTime,this._timeoutActions.Concat(onTimeouts));
        result._startTime = this._startTime;
        return result;
    }
}

有没有人比这个包装有更好的解决方案?

解决方法

我总是开始一个2秒的任务,当它完成时,将你的计算标记为已取消.这可以节省您奇怪的“差异”时间计算.这是一些代码:

Task mainTask = ...; //represents your main "thread"
Task computation = ...; //your main task
Task timeout = TaskEx.Delay(2000);

TaskCompletionSource tcs = new TCS();

TaskEx.WhenAll(timeout,mainTask).ContinueWith(() => tcs.TrySetCancelled());
computation.ContinueWith(() => tcs.TryCopyResultFrom(computation));

Task taskToWaitOn = tcs.Task;

这是伪代码.我只是想展示这项技术.

TryCopyResultFrom用于通过调用TrySetResult()将calculate.Result复制到TaskCompletionSource tcs.

您的应用只使用taskToWaitOn.它将在2s后过渡到取消.如果计算先前完成,它将收到该结果.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读