.net BackgroundWorker 与后台线程

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1506838/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 13:24:08  来源:igfitidea点击:

BackgroundWorker vs background Thread

.netwinformsmultithreadingbackgroundworker

提问by freddy smith

I have a stylistic question about the choice of background thread implementation I should use on a windows form app. Currently I have a BackgroundWorkeron a form that has an infinite (while(true))loop. In this loop I use WaitHandle.WaitAnyto keep the thread snoozing until something of interest happens. One of the event handles I wait on is a "StopThread" event so that I can break out of the loop. This event is signaled when from my overridden Form.Dispose().

我有一个关于我应该在 Windows 窗体应用程序上使用的后台线程实现的选择的文体问题。目前我有一个BackgroundWorker具有无限(while(true))循环的表单。在这个循环中,我WaitHandle.WaitAny用来保持线程暂停直到发生有趣的事情。我等待的事件句柄之一是“ StopThread”事件,以便我可以跳出循环。当从我覆盖的Form.Dispose().

I read somewhere that BackgroundWorkeris really intended for operations that you don't want to tie up the UI with and have an finite end - like downloading a file, or processing a sequence of items. In this case the "end" is unknown and only when the window is closed. Therefore would it be more appropriate for me to use a background Thread instead of BackgroundWorkerfor this purpose?

我在某处读到了一些BackgroundWorker真正适用于您不想将 UI 与 UI 捆绑在一起并具有有限目的的操作的地方 - 例如下载文件或处理一系列项目。在这种情况下,“结束”是未知的,只有当窗口关闭时。因此,我使用后台线程而不是BackgroundWorker为此目的更合适吗?

采纳答案by ParmesanCodice

From my understanding of your question, you are using a BackgroundWorkeras a standard Thread.

根据我对您问题的理解,您使用的BackgroundWorker是标准线程。

The reason why BackgroundWorkeris recommended for things that you don't want to tie up the UI thread is because it exposes some nice events when doing Win Forms development.

BackgroundWorker对于不想占用UI线程的东西,之所以推荐,是因为在做Win Forms开发的时候暴露了一些不错的事件。

Events like RunWorkerCompletedto signal when the thread has completed what it needed to do, and the ProgressChangedevent to update the GUI on the threads progress.

事件喜欢RunWorkerCompleted在线程完成它需要做的事情时发出信号,以及ProgressChanged在线程进度上更新 GUI的事件。

So if you aren'tmaking use of these, I don't see any harm in using a standard Thread for what you need to do.

因此,如果您使用这些,我认为使用标准 Thread 来完成您需要做的事情没有任何害处。

回答by Matt Davis

Some of my thoughts...

我的一些想法...

  1. Use BackgroundWorkerif you have a single task that runs in the background and needs to interact with the UI. The task of marshalling data and method calls to the UI thread are handled automatically through its event-based model. Avoid BackgroundWorker if...
    • your assembly does not have or does not interact directly with the UI,
    • you need the thread to be a foreground thread, or
    • you need to manipulate the thread priority.
  2. Use a ThreadPoolthread when efficiency is desired. The ThreadPool helps avoid the overhead associated with creating, starting, and stopping threads. Avoid using the ThreadPool if...
    • the task runs for the lifetime of your application,
    • you need the thread to be a foreground thread,
    • you need to manipulate the thread priority, or
    • you need the thread to have a fixed identity (aborting, suspending, discovering).
  3. Use the Threadclass for long-running tasks and when you require features offered by a formal threading model, e.g., choosing between foreground and background threads, tweaking the thread priority, fine-grained control over thread execution, etc.
  1. 如果您有一个在后台运行并需要与 UI 交互的任务,请使用BackgroundWorker。将数据和方法调用编组到 UI 线程的任务通过其基于事件的模型自动处理。避免使用 BackgroundWorker,如果...
    • 您的程序集没有或不直接与 UI 交互,
    • 你需要线程是前台线程,或者
    • 您需要操纵线程优先级。
  2. 需要效率时使用ThreadPool线程。ThreadPool 有助于避免与创建、启动和停止线程相关的开销。避免使用线程池,如果...
    • 任务在应用程序的整个生命周期内运行,
    • 你需要线程是前台线程,
    • 您需要操纵线程优先级,或者
    • 您需要线程具有固定的身份(中止、暂停、发现)。
  3. Thread类用于长时间运行的任务,以及当您需要正式线程模型提供的功能时,例如,在前台线程和后台线程之间进行选择、调整线程优先级、对线程执行进行细粒度控制等。

回答by piers7

Pretty much what Matt Davis said, with the following additional points:

几乎马特戴维斯所说的,还有以下几点:

For me the main differentiator with BackgroundWorkeris the automatic marshalling of the completed event via the SynchronizationContext. In a UI context this means the completed event fires on the UI thread, and so can be used to update UI. This is a major differentiator if you are using the BackgroundWorkerin a UI context.

对我来说,主要区别BackgroundWorker在于通过SynchronizationContext. 在 UI 上下文中,这意味着完成的事件在 UI 线程上触发,因此可用于更新 UI。如果您BackgroundWorker在 UI 上下文中使用 ,这是一个主要区别。

Tasks executed via the ThreadPoolcannot be easily cancelled (this includes ThreadPool. QueueUserWorkItemand delegates execute asyncronously). So whilst it avoids the overhead of thread spinup, if you need cancellation either use a BackgroundWorkeror (more likely outside of the UI) spin up a thread and keep a reference to it so you can call Abort().

通过 执行的任务ThreadPool不能轻易取消(这包括ThreadPool.QueueUserWorkItem和委托异步执行)。因此,虽然它避免了线程启动的开销,但如果您需要取消,请使用 aBackgroundWorker或(更可能在 UI 之外)启动一个线程并保留对它的引用,以便您可以调用Abort().

回答by Matt

Also you are tying up a threadpool thread for the lifetime of the background worker, which may be of concern as there are only a finite number of them. I would say that if you are only ever creating the thread once for your app (and not using any of the features of background worker) then use a thread, rather than a backgroundworker/threadpool thread.

此外,您正在为后台工作程序的生命周期占用一个线程池线程,这可能令人担忧,因为它们的数量有限。我会说,如果您只为您的应用程序创建一次线程(并且不使用后台工作程序的任何功能),那么请使用线程,而不是后台工作程序/线程池线程。

回答by Brett Ryan

You know, sometimes it's just easier to work with a BackgroundWorker regardless of if you're using Windows Forms, WPF or whatever technology. The neat part about these guys is you get threading without having to worry too much about where you're thread is executing, which is great for simple tasks.

您知道,有时无论您使用的是 Windows 窗体、WPF 还是任何技术,使用 BackgroundWorker 都会更容易。关于这些家伙的巧妙之处在于,您无需过多担心线程正在执行的位置即可获得线程,这对于简单任务来说非常有用。

Before using a BackgroundWorkerconsider first if you wish to cancel a thread (closing app, user cancellation) then you need to decide if your thread should check for cancellations or if it should be thrust upon the execution itself.

BackgroundWorker如果您想取消一个线程(关闭应用程序,用户取消),那么首先使用考虑之前,您需要决定您的线程是否应该检查取消,或者是否应该将其推到执行本身上。

BackgroundWorker.CancelAsync()will set CancellationPendingto truebut won't do anything more, it's then the threads responsibility to continually check this, keep in mind also that you could end up with a race condition in this approach where your user cancelled, but the thread completed prior to testing for CancellationPending.

BackgroundWorker.CancelAsync()将设置CancellationPendingtrue但不会再做任何事情,然后线程负责不断检查这一点,还请记住,在这种方法中您可能会遇到竞争条件,您的用户取消,但线程在测试之前完成CancellationPending.

Thread.Abort()on the other hand will throw an exception within the thread execution which enforces cancellation of that thread, you must be careful about what might be dangerous if this exception was suddenly raised within the execution though.

Thread.Abort()另一方面,会在线程执行中抛出一个异常,强制取消该线程,但如果在执行过程中突然引发此异常,您必须小心可能会有什么危险。

Threading needs very careful consideration no matter what the task, for some further reading:

无论任务是什么,线程都需要非常仔细地考虑,以供进一步阅读:

Parallel Programming in the .NET FrameworkManaged Threading Best Practices

.NET Framework 中的并行编程托管线程最佳实践

回答by ajs410

I knew how to use threads before I knew .NET, so it took some getting used to when I began using BackgroundWorkers. Matt Davis has summarized the difference with great excellence, but I would add that it's more difficult to comprehend exactly what the code is doing, and this can make debugging harder. It's easier to think about creating and shutting down threads, IMO, than it is to think about giving work to a pool of threads.

我在了解 .NET 之前就知道如何使用线程,所以当我开始使用BackgroundWorkers时需要一些时间来适应。马特戴维斯非常出色地总结了差异,但我要补充的是,要准确理解代码的作用更加困难,这会使调试变得更加困难。考虑创建和关闭线程,IMO,比考虑将工作分配给线程池更容易。

I still can't comment other people's posts, so forgive my momentary lameness in using an answer to address piers7

我仍然无法评论其他人的帖子,所以请原谅我在使用答案来解决 piers 时的一时跛足7

Don't use Thread.Abort();instead, signal an event and design your thread to end gracefully when signaled. Thread.Abort()raises a ThreadAbortExceptionat an arbitrary point in the thread's execution, which can do all kinds of unhappy things like orphan Monitors, corrupt shared state, and so on.
http://msdn.microsoft.com/en-us/library/system.threading.thread.abort.aspx

不要Thread.Abort();改用,发出一个事件信号,并设计你的线程在发出信号时优雅地结束。 在线程执行中的任意点Thread.Abort()引发 a ThreadAbortException,它可以做各种不愉快的事情,例如孤立监视器、损坏的共享状态等。
http://msdn.microsoft.com/en-us/library/system.threading.thread.abort.aspx

回答by David R Tribble

The basic difference is, like you stated, generating GUI events from the BackgroundWorker. If the thread does not need to update the display or generate events for the main GUI thread, then it can be a simple thread.

基本的区别是,就像你说的,从BackgroundWorker. 如果线程不需要为主 GUI 线程更新显示或生成事件,那么它可以是一个简单的线程。

回答by Gandalf

If it ain't broke - fix it till it is...just kidding :)

如果它没有坏 - 修复它直到它......只是在开玩笑:)

But seriously BackgroundWorker is probably very similar to what you already have, had you started with it from the beginning maybe you would have saved some time - but at this point I don't see the need. Unless something isn't working, or you think your current code is hard to understand, then I would stick with what you have.

但是说真的 BackgroundWorker 可能与您已经拥有的非常相似,如果您从一开始就开始使用它,也许您会节省一些时间 - 但在这一点上我认为没有必要。除非某些东西不起作用,或者您认为您当前的代码难以理解,否则我会坚持使用您拥有的代码。

回答by Doomjunky

I want to point out one behavior of BackgroundWorker class that wasn't mentioned yet. You can make a normal Thread to run in background by setting the Thread.IsBackground property.

我想指出 BackgroundWorker 类的一种尚未提及的行为。您可以通过设置 Thread.IsBackground 属性使普通线程在后台运行。

Background threads are identical to foreground threads, except that background threads do not prevent a process from terminating. [1]

后台线程与前台线程相同,只是后台线程不会阻止进程终止。[ 1]

You can test this behavtheitroad by calling the following method in the constructor of your form window.

您可以通过在表单窗口的构造函数中调用以下方法来测试此行为。

void TestBackgroundThread()
{
    var thread = new Thread((ThreadStart)delegate()
    {
        long count = 0;
        while (true)
        {
            count++;
            Debug.WriteLine("Thread loop count: " + count);
        }
    });

    // Choose one option:
    thread.IsBackground = true; // <--- This will make the thread run in background
    thread.IsBackground = false; // <--- This will delay program termination

    thread.Start();
}

When the IsBackground property is set to true and you close the window, then your application will terminate normaly.

当 IsBackground 属性设置为 true 并且您关闭窗口时,您的应用程序将正常终止。

But when the IsBackground property is set to false (by default) and you close the window, then just the window will disapear but the process will still keep running.

但是,当 IsBackground 属性设置为 false(默认情况下)并关闭窗口时,窗口将消失,但进程仍将继续运行。

The BackgroundWorker class utilize a Thread that runs in the background.

BackgroundWorker 类使用在后台运行的线程。

回答by Cesar

A background worker is a class that works in a separate thread, but it provides additional functionality that you don't get with a simple Thread (like task progress report handling).

后台工作者是一个在单独线程中工作的类,但它提供了简单线程无法获得的附加功能(如任务进度报告处理)。

If you don't need the additional features given by a background worker - and it seems you don't - then a Thread would be more appropriate.

如果您不需要后台工作人员提供的附加功能 - 而您似乎不需要 - 那么 Thread 会更合适。