如何尽快处理任务
How to dispose a Task as soon as possible
我有一个 Windows
表单应用程序,我希望在每个 OnLoad
上启动一个异步 Task
并在下一个 OnLoad
上处理。
在 运行 和 Profiler
之后,我看到在每个 OnLoad
之后对象计数变得越来越大。
我知道 GC
不会在您调用 Dispose
或设置为 null
时立即释放内存。我应该覆盖终结器吗?
我也考虑过 CancellationTokenSource
但我
表格
public class MyForm:Form
{
private Task task;
protected override OnLoad()
{
if(this.task!=null)
{
this.task.Dispose();
this.task=null;
}
this.task=Task.Run(()=>....);
}
}
有令牌
public class MyForm:Form
{
private Task task;
private CancellationTokenSource=new CancellationTokenSource();
protected override OnLoad()
{
if(this.task!=null)
{
src.Cancel();
}
try
{
this.task=Task.Run(()=>....,src.Token);
}catch(TaskCancelledException ex)
{
return;
}
}
}
CancellationTokenSource
的问题是,如您所见,我会在之前的 Task
上调用 Cancel
(在第二次 OnLoad
调用时,我会处理第一个Task
),我不知道这是否会在 Try-Catch
块中得到处理。
尽快处理 Task
对象的好方法是什么?这个 Form
会每隔一段时间在计算机上连续重新加载,我不想处理它,只是 Task
您不必根据您的情况处理任务。它仅实现 IDisposable,因为它 可能 分配一个 WaitHandle(这是一次性的):
Internally, Task may allocate a WaitHandle which can be used to wait on the Task to complete. WaitHandle is IDisposable because it holds onto a SafeWaitHandle internally, which is IDisposable. SafeWaitHandle wraps a native handle resource: if the SafeWaitHandle isn’t disposed, eventually its finalizer will get around to cleaning up the wrapped handle, but in the meantime its resources won’t be cleaned up and pressure will be put on the system. By implementing IDisposable on Task, then, we enable developers concerned about aggressively cleaning up these resources to do so in a timely manner.
现在,Microsoft 确实意识到这会造成混淆,因此他们进行了一些更改并创建了一些指南:
We’ve made it much less likely that the Task’s WaitHandle will be allocated at all. We’ve re-implemented WaitAll and WaitAny so that they don’t rely on a Task’s WaitHandle, and we’ve avoided using it internally for any of the new Task or async/await-related functionality introduced in .NET 4.5. Thus, the only way the WaitHandle will be allocated is if you explicitly ask for the Task’s IAsyncResult.AsyncWaitHandle, and that should be quite rare. This means that except in such very infrequent circumstances, disposing of a Task is completely unnecessary.
和
We’ve made Tasks usable even after they’ve been disposed. You can now use all of the public members of Task even after its disposal, and they’ll behave just as they did before disposal. The only member you can’t use is IAsyncResult.AsyncWaitHandle, since that’s what actually gets disposed when you dispose of a Task instance; that property will continue to throw an ObjectDisposedException if you try to use it after the Task has been disposed. This means you should feel freely comfortable caching completed Tasks, knowing that they’re observationally pure. Additionally, moving forward, IAsyncResult usage should drop significantly now that we have async/await and the Task-based Async Pattern, and even for continued usage of IAsyncResult, usage of its AsyncWaitHandle is quite rare.
但是基本的建议是:
“No. Don’t bother disposing of your tasks.” It’s often difficult to find a good place to do so, there’s almost never a reason to do so, and depending on your reference assemblies, you might not even be able to do so.
(source)
我有一个 Windows
表单应用程序,我希望在每个 OnLoad
上启动一个异步 Task
并在下一个 OnLoad
上处理。
在 运行 和 Profiler
之后,我看到在每个 OnLoad
之后对象计数变得越来越大。
我知道 GC
不会在您调用 Dispose
或设置为 null
时立即释放内存。我应该覆盖终结器吗?
我也考虑过 CancellationTokenSource
但我
表格
public class MyForm:Form
{
private Task task;
protected override OnLoad()
{
if(this.task!=null)
{
this.task.Dispose();
this.task=null;
}
this.task=Task.Run(()=>....);
}
}
有令牌
public class MyForm:Form
{
private Task task;
private CancellationTokenSource=new CancellationTokenSource();
protected override OnLoad()
{
if(this.task!=null)
{
src.Cancel();
}
try
{
this.task=Task.Run(()=>....,src.Token);
}catch(TaskCancelledException ex)
{
return;
}
}
}
CancellationTokenSource
的问题是,如您所见,我会在之前的 Task
上调用 Cancel
(在第二次 OnLoad
调用时,我会处理第一个Task
),我不知道这是否会在 Try-Catch
块中得到处理。
尽快处理 Task
对象的好方法是什么?这个 Form
会每隔一段时间在计算机上连续重新加载,我不想处理它,只是 Task
您不必根据您的情况处理任务。它仅实现 IDisposable,因为它 可能 分配一个 WaitHandle(这是一次性的):
Internally, Task may allocate a WaitHandle which can be used to wait on the Task to complete. WaitHandle is IDisposable because it holds onto a SafeWaitHandle internally, which is IDisposable. SafeWaitHandle wraps a native handle resource: if the SafeWaitHandle isn’t disposed, eventually its finalizer will get around to cleaning up the wrapped handle, but in the meantime its resources won’t be cleaned up and pressure will be put on the system. By implementing IDisposable on Task, then, we enable developers concerned about aggressively cleaning up these resources to do so in a timely manner.
现在,Microsoft 确实意识到这会造成混淆,因此他们进行了一些更改并创建了一些指南:
We’ve made it much less likely that the Task’s WaitHandle will be allocated at all. We’ve re-implemented WaitAll and WaitAny so that they don’t rely on a Task’s WaitHandle, and we’ve avoided using it internally for any of the new Task or async/await-related functionality introduced in .NET 4.5. Thus, the only way the WaitHandle will be allocated is if you explicitly ask for the Task’s IAsyncResult.AsyncWaitHandle, and that should be quite rare. This means that except in such very infrequent circumstances, disposing of a Task is completely unnecessary.
和
We’ve made Tasks usable even after they’ve been disposed. You can now use all of the public members of Task even after its disposal, and they’ll behave just as they did before disposal. The only member you can’t use is IAsyncResult.AsyncWaitHandle, since that’s what actually gets disposed when you dispose of a Task instance; that property will continue to throw an ObjectDisposedException if you try to use it after the Task has been disposed. This means you should feel freely comfortable caching completed Tasks, knowing that they’re observationally pure. Additionally, moving forward, IAsyncResult usage should drop significantly now that we have async/await and the Task-based Async Pattern, and even for continued usage of IAsyncResult, usage of its AsyncWaitHandle is quite rare.
但是基本的建议是:
“No. Don’t bother disposing of your tasks.” It’s often difficult to find a good place to do so, there’s almost never a reason to do so, and depending on your reference assemblies, you might not even be able to do so.
(source)