在 TPL 任务对象上不调用 Dispose() 是否可以接受? [英] Is it considered acceptable to not call Dispose() on a TPL Task object?

查看:17
本文介绍了在 TPL 任务对象上不调用 Dispose() 是否可以接受?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想触发一个在后台线程上运行的任务.我不想等待任务完成.

I want to trigger a task to run on a background thread. I don't want to wait on the tasks completion.

在 .net 3.5 中我会这样做:

In .net 3.5 I would have done this:

ThreadPool.QueueUserWorkItem(d => { DoSomething(); });

在 .net 4 中,TPL 是建议的方式.我看到推荐的常见模式是:

In .net 4 the TPL is the suggested way. The common pattern I have seen recommended is:

Task.Factory.StartNew(() => { DoSomething(); });

但是,StartNew() 方法返回一个 Task 实现 IDisposable 的对象.这个似乎被推荐这种模式的人忽视了.关于 Task.Dispose() 方法说:

However, the StartNew() method returns a Task object which implements IDisposable. This seems to be overlooked by people who recommend this pattern. The MSDN documentation on the Task.Dispose() method says:

在释放对任务的最后一次引用之前,始终调用 Dispose."

"Always call Dispose before you release your last reference to the Task."

在任务完成之前您不能对它调用 dispose,因此让主线程等待并调用 dispose 将首先破坏在后台线程上执行的点.似乎也没有任何可用于清理的已完成/已完成事件.

You can't call dispose on a task until it is completed, so having the main thread wait and call dispose would defeat the point of doing on a background thread in the first place. There also doesn't seem to be any completed/finished event that could be used for cleanup.

Task 类的 MSDN 页面没有对此发表评论,而Pro C#2010..."一书推荐了相同的模式,并且没有对任务处理发表评论.

The MSDN page on the Task class doesn't comment on this, and the book "Pro C#2010..." recommends the same pattern and makes no comment on task disposal.

我知道如果我离开它,终结器最终会抓住它,但是当我做很多火时,它会回来咬我吗?忘记这样的任务,终结器线程会不堪重负?

I know if I just leave it the finalizer will catch it in the end, but is this going to come back and bite me when I'm doing lots of fire & forget tasks like this and the finalizer thread gets overwhelmed?

所以我的问题是:

  • 在这种情况下,在 Task 类上不调用 Dispose() 是否可以接受?如果是这样,为什么以及是否存在风险/后果?
  • 是否有任何文档对此进行了讨论?
  • 或者是否有适当的方法来处理我遗漏的 Task 对象?
  • 或者有没有另一种方式来做火&忘记了 TPL 的任务?
  • Is it acceptable to not call Dispose() on the Task class in this case? And if so, why and are there risks/consequences?
  • Is there any documentation that discusses this?
  • Or is there an appropriate way of disposing of the Task object that I've missed?
  • Or is there another way of doing fire & forget tasks with the TPL?

推荐答案

有一个关于这个的讨论 在 MSDN 论坛中.

There is a discussion about this in the MSDN forums.

Stephen Toub,Microsoft pfx 团队的一名成员有这样的说法:

Stephen Toub, a member of the Microsoft pfx team has this to say:

Task.Dispose 由于任务而存在可能包装一个事件句柄在等待任务时使用完成,如果等待线程实际上必须阻塞(如反对旋转或潜在执行它正在等待的任务).如果你所做的只是使用继续,该事件句柄将永远不会被分配
...
依靠最终确定来处理事情可能会更好.

Task.Dispose exists due to Task potentially wrapping an event handle used when waiting on the task to complete, in the event the waiting thread actually has to block (as opposed to spinning or potentially executing the task it's waiting on). If all you're doing is using continuations, that event handle will never be allocated
...
it's likely better to rely on finalization to take care of things.

更新(2012 年 10 月)
Stephen Toub 发布了一篇名为 我需要吗?处理任务?,其中提供了更多细节,并解释了 .Net 4.5 中的改进.

Update (Oct 2012)
Stephen Toub has posted a blog titled Do I need to dispose of Tasks? which gives some more detail, and explains the improvements in .Net 4.5.

总而言之:您不需要在 99% 的情况下处理 Task 对象.

In summary: You don't need to dispose of Task objects 99% of the time.

处置对象有两个主要原因:及时、确定性地释放非托管资源,以及避免运行对象终结器的成本.大多数情况下,这些都不适用于Task:

There are two main reasons to dispose an object: to free up unmanaged resources in a timely, deterministic way, and to avoid the cost of running the object's finalizer. Neither of these apply to Task most of the time:

  1. 从 .Net 4.5 开始,Task 分配内部等待句柄(Task 对象中唯一的非托管资源)的唯一时间是当您显式使用 <Task 的 code>IAsyncResult.AsyncWaitHandle 和
  2. Task 对象本身没有终结器;句柄本身被包装在一个带有终结器的对象中,所以除非它被分配,否则没有终结器可以运行.
  1. As of .Net 4.5, the only time a Task allocates the internal wait handle (the only unmanaged resource in the Task object) is when you explicitly use the IAsyncResult.AsyncWaitHandle of the Task, and
  2. The Task object itself doesn't have a finalizer; the handle is itself wrapped in an object with a finalizer, so unless it's allocated, there's no finalizer to run.

这篇关于在 TPL 任务对象上不调用 Dispose() 是否可以接受?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆