gpt4 book ai didi

c# - CancellationTokenSource.CancelAfter() 是否有漏洞?

转载 作者:太空狗 更新时间:2023-10-30 00:43:33 25 4
gpt4 key购买 nike

发布Async Targeting Pack提示我使用 ILSpy看看是什么Task-based Asynchronous Pattern (TAP)那里提供了扩展方法(其中一些我已经自己实现用于 VS2010)。我偶然发现了 .CancelAfter(TimeSpan) CancellationTokenSource 的方法(在 .NET 4.0 的 Async Targeting Pack 中作为扩展方法,但在 .NET 4.5 中是实例方法)并认为它可能是实现各种超时的好方法本身没有超时但支持取消的操作。

但是查看 Async Targeting Pack 中的实现,似乎如果关联的 Task 完成或取消,计时器会继续运行。

/// <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");
}
Timer timer = new Timer(delegate(object self)
{
((IDisposable)self).Dispose();
try
{
source.Cancel();
}
catch (ObjectDisposedException)
{
}
});
timer.Change(dueTime, -1);
}

假设我使用此方法为经常使用的基于 TAP 的操作提供超时,并使用 .CancelAfter() 对其进行包装。现在假设用户提供 5 分钟(300 秒)的超时值,并且每秒调用此操作 100 次,这些操作在几毫秒后全部成功完成。在每秒 100 次调用的 300 秒后,所有这些操作将累积 30,000 个正在运行的计时器,即使任务很久以前就已成功完成。它们最终都会消失并运行上述委托(delegate),这可能会抛出 ObjectDisposedException 等。

这不是有点漏水、不可扩展的行为吗?当我实现超时时,我使用了 Task/TaskEx.Delay(TimeSpan, CancellationToken) 并且当相关任务结束时,我取消了 .Delay() 以便计时器将被停止和处置(毕竟它是一个 IDisposable,并且它确实包含非托管资源)。这种清理是否过于热心?让数以万计的计时器同时运行(并可能在之后抛出数以万计的捕获异常)的成本对普通应用程序的性能真的无关紧要吗?与实际完成的工作相比,.CancelAfter() 的开销和漏洞是否几乎总是微不足道的,通常应该被忽略?

最佳答案

尝试一下,将其推向极限,看看会发生什么。我无法让工作设置超过 90 MB 的一千万个计时器。 System.Threading.Timer 非常便宜。

using System;
using System.Threading;

class Program {
public static int CancelCount;
static void Main(string[] args) {
int count = 1000 * 1000 * 10;
for (int ix = 0; ix < count; ++ix) {
var token = new CancellationTokenSource();
token.CancelAfter(500);
}
while (CancelCount < count) {
Thread.Sleep(100);
Console.WriteLine(CancelCount);
}
Console.WriteLine("done");
Console.ReadLine();
}
}

static class Extensions {
public static void CancelAfter(this CancellationTokenSource source, int dueTime) {
Timer timer = new Timer(delegate(object self) {
Interlocked.Increment(ref Program.CancelCount);
((IDisposable)self).Dispose();
try {
source.Cancel();
}
catch (ObjectDisposedException) {
}
});
timer.Change(dueTime, -1);
}
}

关于c# - CancellationTokenSource.CancelAfter() 是否有漏洞?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10715688/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com