我很难把头放在扩展方法上。它们是静态类中的静态方法。它们如何在内部初始化?例如,我写了下面的扩展方法。它是线程安全的吗?
public static async Task TimeoutAfter(this Task task, TimeSpan timeSpan)
{
var cts = new CancellationTokenSource();
try
{
if (task.IsCompleted || timeSpan == Timeout.InfiniteTimeSpan)
return;
if (timeSpan == TimeSpan.Zero)
throw new TimeoutException();
if (task == await Task.WhenAny(task, Task.Delay(timeSpan, cts.Token)))
{
cts.Cancel();
await task;
}
else
{
throw new TimeoutException();
}
}
finally
{
cts.Dispose();
}
}
所有扩展方法要做的就是转
var result = myTask.TimeoutAfter(TimeSpan.FromSecconds(5));
进入
var result = ExtensionMethodClass.TimeoutAfter(myTask, TimeSpan.FromSecconds(5));
没别的。因此,无论函数是否是扩展方法,都根本不会影响其行为,这只是说服程序员不必从我上面的示例中键入长版本。
至于您的代码是否是线程安全的,首先您需要了解“线程安全”的含义。我强烈建议您阅读埃里克·利珀特(Eric Lippert)的文章“什么叫做“线程安全”? ”,它将极大地帮助您了解线程安全的含义。
您的代码不会从其作用域访问或更改任何外部变量,因此该函数本身是线程安全的,但这并不意味着它不能以“线程不安全”的方式使用。幸运的是,您Task
和TimeSpan
我俩都很幸运,并且在它们的所有方法和属性上都保证了线程安全,因此您不太可能遇到任何线程安全问题。
不管怎么说,您确实有一个带有竞争条件的错误。如果task.IsCompleted
返回true并task
引发异常,则永远不会收到该异常的通知。另外,timeSpan == Timeout.InfiniteTimeSpan
即使传入的任务仍在运行,函数仍将立即返回完成的任务。await
即使您不打算进行超时,也需要执行任务。另外,您的try / finally可以简化为一个using
语句
public static async Task TimeoutAfter(this Task task, TimeSpan timeSpan)
{
using(var cts = new CancellationTokenSource())
{
if (task.IsCompleted || timeSpan == Timeout.InfiniteTimeSpan)
{
await task;
return;
}
if (timeSpan == TimeSpan.Zero)
throw new TimeoutException();
if (task == await Task.WhenAny(task, Task.Delay(timeSpan, cts.Token)))
{
cts.Cancel();
await task;
}
else
{
throw new TimeoutException();
}
}
}
最后,如果您还没有做过,那么您将需要制作一个版本,Task<T>
以防万一您要使返回结果的任务超时。
public static async Task<T> TimeoutAfter<T>(this Task<T> task, TimeSpan timeSpan)
{
using(var cts = new CancellationTokenSource())
{
if (task.IsCompleted || timeSpan == Timeout.InfiniteTimeSpan)
{
return await task
}
if (timeSpan == TimeSpan.Zero)
throw new TimeoutException();
if (task == await Task.WhenAny(task, Task.Delay(timeSpan, cts.Token)))
{
cts.Cancel();
return await task;
}
else
{
throw new TimeoutException();
}
}
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句