微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c# – 异步延迟超时任务

我有一个异步操作依赖于另一个服务器,它需要大部分随机的时间来完成.当异步操作正在运行时,“主线程”中也会进行处理,这也需要一段随机的时间来完成.

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

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

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后过渡到取消.如果计算先前完成,它将收到该结果.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐