我需要处理任务吗?

时间:2023-02-09 15:43:12

I am having fun working with System.Threading.Tasks. Many of the code samples I see, however, look something like so:

我很高兴使用System.Threading.Tasks。但是,我看到的许多代码示例都是这样的:

Dim lcTask = Task.Factory.StartNew(Sub() DoSomeWork())
Dim lcTaskLong = Task.Factory.StartNew(Sub() DoSomeWork(), TaskCreationOptions.LongRunning)
Task.WaitAll(lcTask, lcTaskLong)

That's the extent of the sample.
Tasks implement IDisposable, so obviously I'm supposed to dispose of them, but what if I just want to "Fire and Forget"?

这就是样本的范围。任务实现IDisposable,所以很明显我应该处理它们,但是如果我只是想要“Fire and Forget”呢?

If I don't dispose, will I leak threads/handles/memory/karma? Am I using tasks "wrong"? (Should just use a delegate and leave tasks alone?)

如果我不处理,我会泄漏线程/句柄/记忆/业力吗?我使用“错误”的任务吗? (应该只使用代表并单独留下任务吗?)

Can I dispose in a ContinueWith()? (That seems like playing Russian Roulette.)

我可以处理ContinueWith()吗? (这好像在玩俄罗斯轮盘赌。)

1 个解决方案

#1


18  

While the normal rule of thumb is to always call Dispose() on all IDisposable implementations, Task and Task<T> are often one case where it's better to let the finalizer take care of this.

虽然通常的经验法则是始终在所有IDisposable实现上调用Dispose(),但Task和Task 通常是一种情况,最好让终结器处理这个问题。

The reason Task implements IDisposable is mainly due to an internal WaitHandle. This is required to allow task continuations to work properly, and only used when there is a continuation on a Task. If there is no continuation, the Task's Dispose method has no real effect - so in this case, it's not required.

Task实现IDisposable的原因主要是由于内部WaitHandle。这是允许任务继续正常工作所必需的,并且仅在任务上有延续时使用。如果没有延续,Task的Dispose方法没有实际效果 - 所以在这种情况下,它不是必需的。

That being said, in most cases where there is a Task continuation, it's often very, very difficult to write your code in a way that allows you to properly call Dispose(). Using statements typically do not work with Task instances, since the Task call is typically asynchronous in nature. It's very easy to dispose of the Task far too early, especially when using the using statement.

话虽如此,在大多数情况下,如果有任务延续,通常非常非常难以以允许您正确调用Dispose()的方式编写代码。使用语句通常不适用于Task实例,因为Task调用本质上通常是异步的。过早地处理Task非常容易,尤其是在使用using语句时。

If, in your case, it's relatively simple to keep a reference to the Task and call Dispose() on it correctly, I would do so. However, if this is going to cause your logic to get much more complex, I would typically pretend that Task isn't IDisposable, and allow it to be cleaned up in the finalizer for the Task.

在你的情况下,如果保持对Task的引用并正确调用Dispose()相对简单,我会这样做。但是,如果这会导致您的逻辑变得更加复杂,我通常会假装Task不是IDisposable,并允许在Task的终结器中清理它。

For more details, I'd recommend reading this thread on the MSDN forums where Stephen Toub describes why Task implements IDisposable in detail, and provides similar guidance to my suggestion above.

有关更多详细信息,我建议在MSDN论坛上阅读此主题,其中Stephen Toub描述了Task为何详细实现IDisposable,并为上述建议提供了类似的指导。

#1


18  

While the normal rule of thumb is to always call Dispose() on all IDisposable implementations, Task and Task<T> are often one case where it's better to let the finalizer take care of this.

虽然通常的经验法则是始终在所有IDisposable实现上调用Dispose(),但Task和Task 通常是一种情况,最好让终结器处理这个问题。

The reason Task implements IDisposable is mainly due to an internal WaitHandle. This is required to allow task continuations to work properly, and only used when there is a continuation on a Task. If there is no continuation, the Task's Dispose method has no real effect - so in this case, it's not required.

Task实现IDisposable的原因主要是由于内部WaitHandle。这是允许任务继续正常工作所必需的,并且仅在任务上有延续时使用。如果没有延续,Task的Dispose方法没有实际效果 - 所以在这种情况下,它不是必需的。

That being said, in most cases where there is a Task continuation, it's often very, very difficult to write your code in a way that allows you to properly call Dispose(). Using statements typically do not work with Task instances, since the Task call is typically asynchronous in nature. It's very easy to dispose of the Task far too early, especially when using the using statement.

话虽如此,在大多数情况下,如果有任务延续,通常非常非常难以以允许您正确调用Dispose()的方式编写代码。使用语句通常不适用于Task实例,因为Task调用本质上通常是异步的。过早地处理Task非常容易,尤其是在使用using语句时。

If, in your case, it's relatively simple to keep a reference to the Task and call Dispose() on it correctly, I would do so. However, if this is going to cause your logic to get much more complex, I would typically pretend that Task isn't IDisposable, and allow it to be cleaned up in the finalizer for the Task.

在你的情况下,如果保持对Task的引用并正确调用Dispose()相对简单,我会这样做。但是,如果这会导致您的逻辑变得更加复杂,我通常会假装Task不是IDisposable,并允许在Task的终结器中清理它。

For more details, I'd recommend reading this thread on the MSDN forums where Stephen Toub describes why Task implements IDisposable in detail, and provides similar guidance to my suggestion above.

有关更多详细信息,我建议在MSDN论坛上阅读此主题,其中Stephen Toub描述了Task为何详细实现IDisposable,并为上述建议提供了类似的指导。