[英]Implementing async timeout using poor mans async/await constructs in .Net 4.0
C# 5.0 async/await constructs are awesome, unfortunately yet Microsoft only shown a release candidate of both .NET 4.5 and VS 2012, and it will take some time until these technologies will get widely adopted in our projects. C#5.0异步/等待构造非常棒,但遗憾的是,微软只展示了.NET 4.5和VS 2012的候选版本,这些技术将在我们的项目中得到广泛采用需要一些时间。
In Stephen Toub's Asynchronous methods, C# iterators, and Tasks I've found a replacement that can be nicely used in .NET 4.0. 在Stephen Toub的异步方法,C#迭代器和任务中,我找到了一个可以在.NET 4.0中很好地使用的替代方法。 There are also a dozen of other implementations that make it possible using the approach even in .NET 2.0 though they seem little outdated and less feature-rich.
还有十几个其他实现甚至可以在.NET 2.0中使用该方法,尽管它们看起来很少过时且功能较少。
So now my .NET 4.0 code looks like (the commented sections show how it is done in .NET 4.5): 所以现在我的.NET 4.0代码看起来像(注释部分显示它是如何在.NET 4.5中完成的):
//private async Task ProcessMessageAsync()
private IEnumerable<Task> ProcessMessageAsync()
{
//var udpReceiveResult = await udpClient.ReceiveAsync();
var task = Task<UdpAsyncReceiveResult>
.Factory
.FromAsync(udpClient.BeginReceive, udpClient.EndReceive, null);
yield return task;
var udpReceiveResult = task.Result;
//... blah blah blah
if (message is BootstrapRequest)
{
var typedMessage = ((BootstrapRequest)(message));
// !!! .NET 4.0 has no overload for CancellationTokenSource that
// !!! takes timeout parameter :(
var cts
= new CancellationTokenSource(BootstrapResponseTimeout); // Error here
//... blah blah blah
// Say(messageIPEndPoint, responseMessage, cts.Token);
Task.Factory.Iterate(Say(messageIPEndPoint, responseMessage, cts.Token));
}
}
Looks little ugly though it does the job 看起来有点难看虽然它能完成这项工作
When using CancellationTokenSource in .NET 4.5 there is a constructor that takes timespan as a timeout parameter, so that resulting CancellationTokenSource
cancels within specified period of time. 在.NET 4.5中使用CancellationTokenSource时 ,有一个构造函数将时间跨度作为超时参数,以便在指定的时间段内取消生成的
CancellationTokenSource
。
.Net 4.0 is not able to timeout, so what is the correct way of doing that in .Net 4.0? .Net 4.0无法超时,那么在.Net 4.0中这样做的正确方法是什么?
FWIW, you can use async/await in 4.0 projects, just use the async targeting pack . FWIW,您可以在4.0项目中使用async / await,只需使用异步定位包即可 。 Works Great For Me!
适合我的作品!
Does this really have anything to do with async/await? 这真的与async / await有关吗? Looks like you're just needing a way to cancel the token, independently of async/await, right?
看起来你只需要一种取消令牌的方法,独立于异步/等待,对吗? In that case, could you simply create a Timer that calls Cancel after the timeout?
在这种情况下,您可以简单地创建一个在超时后调用取消的Timer吗?
new Timer(state => cts.Cancel(), null, BootstrapResponseTimeout, Timeout.Infinite);
EDIT 编辑
My initial response above is the basic idea, but a more robust solution is can be found in Is CancellationTokenSource.CancelAfter() leaky? 我上面的初步回答是基本的想法,但是在一个更好的解决方案可以在Is CancellationTokenSource.CancelAfter()漏洞中找到? (actually the .Net 4.5 implementation of the constructor you're seeking).
(实际上是你正在寻求的构造函数的.Net 4.5实现)。 Here's a function you can use to create timeout tokens based on that code.
这是一个可用于根据该代码创建超时令牌的函数。
public static CancellationTokenSource CreateTimeoutToken(int dueTime) {
if (dueTime < -1) {
throw new ArgumentOutOfRangeException("dueTime");
}
var source = new CancellationTokenSource();
var timer = new Timer(self => {
((Timer)self).Dispose();
try {
source.Cancel();
} catch (ObjectDisposedException) {}
});
timer.Change(dueTime, -1);
return source;
}
You can still use CancelAfter()
, which is an extension method in Microsoft.Bcl.Async
which is very similar to accepted answer above. 您仍然可以使用
CancelAfter()
,它是Microsoft.Bcl.Async
的扩展方法,与上面接受的答案非常相似。
This is the refereance souce code when I press F12 to see the implementation of CancelAfter()
: 当我按F12查看
CancelAfter()
的实现时,这是参考源代码:
/// <summary>Cancels the <see cref="T:System.Threading.CancellationTokenSource" /> after the specified duration.</summary>
/// <param name="source">The CancellationTokenSource.</param>
/// <param name="dueTime">The due time in milliseconds for the source to be canceled.</param>
public static void CancelAfter(this CancellationTokenSource source, int dueTime)
{
if (source == null)
throw new NullReferenceException();
if (dueTime < -1)
throw new ArgumentOutOfRangeException("dueTime");
Contract.EndContractBlock();
Timer timer = (Timer) null;
timer = new Timer((TimerCallback) (state =>
{
timer.Dispose();
TimerManager.Remove(timer);
try
{
source.Cancel();
}
catch (ObjectDisposedException ex)
{
}
}), (object) null, -1, -1);
TimerManager.Add(timer);
timer.Change(dueTime, -1);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.