我的另一个问题基本上需要这个,所以我想在这里分享我的通用解决方案。
我在使用HttpClient任务进行Web请求时遇到了麻烦,因为它们基本上永远不会完成;所以程序或线程会挂起。我需要一种简单的方法来为任务添加超时,以便如果超时先过期,则正常返回或返回已取消。
可以在此处找到一些替代方法: http://blogs.msdn.com/b/pfxteam/archive/2011/11/10/10235834.aspx
我的另一个问题基本上需要这个,所以我想在这里分享我的通用解决方案。
我在使用HttpClient任务进行Web请求时遇到了麻烦,因为它们基本上永远不会完成;所以程序或线程会挂起。我需要一种简单的方法来为任务添加超时,以便如果超时先过期,则正常返回或返回已取消。
可以在此处找到一些替代方法: http://blogs.msdn.com/b/pfxteam/archive/2011/11/10/10235834.aspx
从技术上讲,您无法在一段时间后强制取消任务。最好的方法是创建一个新任务,在给定的时间段后将其标记为已取消,或者如果其他任务及时完成,则标记为已完成。
需要注意的关键点是,操作超时并不会停止任务继续工作,只有在达到超时时间时,所有这个新任务的延续才会“提前”触发。
利用CancellationToken
方法做到这一点非常简单:
var newTask = task.ContinueWith(t => { }
, new CancellationTokenSource(timeoutTime).Token);
我们可以将此模式与 WhenAny
结合使用,以轻松确保任何异常都能正确传播到后续操作。 对于具有/不具有结果的任务,还需要进行拷贝:
public static Task WithTimeout(Task task, TimeSpan timeout)
{
var delay = task.ContinueWith(t => { }
, new CancellationTokenSource(timeout).Token);
return Task.WhenAny(task, delay).Unwrap();
}
public static Task<T> WithTimeout<T>(Task<T> task, TimeSpan timeout)
{
var delay = task.ContinueWith(t => t.Result
, new CancellationTokenSource(timeout).Token);
return Task.WhenAny(task, delay).Unwrap();
}
当超时发生时,您可以使用CancellationTokenSource:
var DefualtTimeout = 5000;
var cancelToken = new CancellationTokenSource();
var taskWithTimeOut = Task.Factory.StartNew( t =>
{
var token = (CancellationToken)t;
while (!token.IsCancellationRequested)
{
// Here your work
}
token.ThrowIfCancellationRequested();
}, cancelToken.Token, cancelToken.Token);
方法一:
if (!taskWithTimeOut.Wait(DefualtTimeout, cancelToken.Token))
{
cancelToken.Cancel();
}
方法二:
SpinWait.SpinUntil(() => taskWithTimeOut.IsCompleted, new TimeSpan(0, 0, 0, 0, DefualtTimeout ));
方法三:
您可以将该方法设置为异步,并在任务之前写入 await taskWithTimeOut.Wait..
,这样UI就不会被阻塞。