【问题标题】:Proper way to Dispose of a BackGroundWorker处理 BackGroundWorker 的正确方法
【发布时间】:2010-03-30 01:36:09
【问题描述】:

这是处置 BackGroundWorker 的正确方法吗?我不确定在调用 .Dispose() 之前是否需要删除事件。在 RunWorkerCompleted 委托中调用 .Dispose() 也可以吗?

public void RunProcessAsync(DateTime dumpDate)
{
    BackgroundWorker worker = new BackgroundWorker();
    worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
    worker.DoWork += new DoWorkEventHandler(worker_DoWork);
    worker.RunWorkerAsync(dumpDate);
}

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    // Do Work here
}

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;
    worker.RunWorkerCompleted -= new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
    worker.DoWork -= new DoWorkEventHandler(worker_DoWork);
    worker.Dispose();
}

【问题讨论】:

  • 这是表单的后台工作人员吗?
  • 是的,尽管我以编程方式创建了 BGW,而不是将其放在设计器中的表单上。如图所示,当我想运行线程时会创建 BGW。这个想法是在每次调用线程时创建一个不同的 BGW,并在它们完成时处理它们。
  • 我知道这是 aaaaaaaages 以前的事情,它是注册处理程序的旧方式,但是,这个:-= new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted) 正在创建一个包装 worker_RunWorkerCompleted 的新委托,所以它不是与第一个实例相同的委托,并且第一个仍将挂起,附加到后台工作人员。要确保删除处理程序,请使用:+= worker_RunWorkerCompleted 和 -= worker_RunWorkerCompleted(不使用“新 xxxEventHandler”包装器。

标签: c# .net multithreading backgroundworker


【解决方案1】:

BackgroundWorker 派生自组件。组件实现了 IDisposable 接口。这反过来又使 BackgroundWorker 继承了 Dispose() 方法。

从组件派生对 Windows 窗体程序员来说是一种便利,他们可以将 BGW 从工具箱拖放到窗体上。一般来说,组件有些可能需要处理一些东西。 Windows 窗体设计器会自动处理此问题,在 Designer.cs 文件中查找“组件”字段的窗体。它自动生成的 Dispose() 方法为所有组件调用 Dispose() 方法。

但是,BackgroundWorker 实际上没有任何需要处理的成员。它不会覆盖 Dispose()。它的基本实现 Component.Dispose() 仅确保从“组件”集合中删除该组件。并引发 Disposed 事件。但不会以其他方式处置任何东西。

长话短说:如果您在表单上放置了 BGW,那么一切都会自动处理,您无需提供帮助。如果您没有将它放在表单上,​​那么它就不是组件集合中的元素,无需执行任何操作。

您不必调用 Dispose()

【讨论】:

  • 我无法反驳。但更喜欢总是思考:“需要处理的类可以包装什么样的对象?”看看。我很难编写没有意义的代码,并且不相信有一天它会有意义。它也可以反过来工作:Thread 类确实有一次性对象,但没有实现 IDisposable。各有各的。
  • 我明白了。不需要处置 BGW,因为它没有要处置的东西?我曾经读过,如果事件没有被删除,当依赖于它们的对象被释放时,它们可以继续挂起以防止释放资源。从来都不是这样吗?
  • @galford:从技术上讲,连接到 BGW 事件的事件处理程序可以防止表单对象被垃圾收集。这在实践中永远不会发生,因为您总是让 BGW 对象成为表单的成员。他们将同时收集两个垃圾。
  • 我明白了,那么我当前的实现是缺少的,因为我需要添加 this.Components.Add(BGW),并且还要使 BGW 成为表单中的持久对象,而不是每次创建 BGW调用 RunProcessAsync 方法。这就说得通了。 BGW 无论如何都不是内存密集型的,每次重新创建它只会使用比所需更多的 cpu。
【解决方案2】:

游戏迟到了,但我刚刚遇到了一个与您的问题相关的场景,我想我会分享。如果您在类级别创建您的工作人员并在不关闭应用程序的情况下在后续操作中重用它,如果您在完成后不删除事件,它们将在每次后续执行时递增并运行多次。

worker.RunWorkerCompleted -= new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.DoWork -= new DoWorkEventHandler(worker_DoWork);

如果没有上述内容,我的 DoWork 第一次会触发一次,第二次会触发两次,依此类推。这对大多数人来说可能是不费吹灰之力,但我花了一点时间才弄清楚,所以希望这对其他人有帮助.

【讨论】:

  • 您能否提供更详细的方案代码。我使用 BW,这(据我所知)从未发生在我身上
  • 不写一个完整的例子就没有更多的解释,但我会尝试。如果“worker”是在使用它的方法之外定义的(即在应用程序级别全局定义),但您在其中一种方法中订阅了该工作者,而没有在每次迭代中删除所述订阅,它的订阅将继续呈指数增长。
  • 我的理解是你在订阅事件的方法被调用了多次。如果是这样:是的,当然;如果没有,我还是没掌握。
  • 这正是我要说的。仅陈述一年多前在发现 BackgroundWorker 的用法时的一个明显观察。
  • 当然,它会触发多次,您要添加主体并完成多次
【解决方案3】:

worker.Dispose() 不是必需的,因为会自动调用Dispose()。但在处理对象之前,您需要删除所有事件处理程序。

article 告知我们这一点。

worker.RunWorkerCompleted -= new RunWorkerCompletedEventHandle(worker_RunWorkerCompleted);
worker.DoWork -= new DoWorkEventHandler(worker_DoWork);

【讨论】:

  • 如果文章提到删除事件处理程序曾经是真的,现在不再是这样了。在链接文章的所有版本中,均未提及事件。
  • 是谁自动调用的?据我所知,也在您引用的链接中,由程序员调用 Dispose。唯一可以保证调用的情况是使用 using 关键字时。
【解决方案4】:

是的,这看起来是正确的。当然,使用 using 块更好地处理一次性对象,但这里没有这个选项。

我通常创建具有表单生命周期的后台处理程序,重用它们,并让设计器代码处理表单关闭时的处理。少考虑。

【讨论】:

  • 这就是我过去一直这样做的方式。虽然我没有意识到在设计时在 WinForm 上放置 BackGroundWorker 会将 BGW 添加到在处置表单时将被处置的对象列表中。我通常以编程方式创建 BGW。
【解决方案5】:

如果它在“WinForms”表单上,让容器处理它(请参阅 Form.Designer.xyz 文件中生成的Dispose 代码)

在实践中,我发现您可能需要创建容器的实例并将工作人员(或其他公司)添加到其中,如果有人知道更正式的方式来做这件事,请大声疾呼!!

PK :-)

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        // watch the disposed event....
        backgroundWorker1.Disposed += new EventHandler(backgroundWorker1_Disposed);

        // try with and without the following lines
        components = new Container();
        components.Add(backgroundWorker1);
    }

    void backgroundWorker1_Disposed(object sender, EventArgs e)
    {
        Debug.WriteLine("backgroundWorker1_Disposed");
    }

//... from the Designer.xyz file ...

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-08
    • 2011-02-28
    • 2016-01-15
    • 2016-05-02
    • 1970-01-01
    • 1970-01-01
    • 2010-09-20
    相关资源
    最近更新 更多