.NET Backgroundworker对象的线程优先级

9
我正在开发一个应用程序,尝试使用.NET Backgroundworker对象。网络上的所有资料都说这个对象在“后台”运行,但是我无法确认这个后台线程是否确实以“低优先级”模式运行。这个问题的原因是在Windows中(我假设),后台任务可以在“正常”或“低于正常”或“低”优先级模式下运行。
在我的应用程序中,我尝试在DoWork函数内部通过调用...来自己设置优先级。
Thread.CurrentThread.Priority=ThreadPriority.Lowest

但是这似乎没有任何效果。BackgroundWorker是否忽略了此调用?

我想再解释一下:

我的应用程序是一个互联网客户端,它从一个仓库收集温度、湿度等实时数据,并使用system.net.webclient.UploadValuesAsync(...)调用将其上传到网页(不是Web服务)。

我已经编写了应用程序,使得客户端GUI从仓库收集数据,对其进行时间戳处理,然后将其排队上传,如下所示:

...

Synclock objlock
    debug.print("Queueing reading...")
    dataQ.Enque(reading)
End Synclock
...

BackgroundWorker的DoWork函数会按照以下方式出队并上传...

..............

Do
        if dataQ.count() <> 0 then
            Synclock objlock
              reading = dataQ.DeQue()
            End Synclock
            Dim client As New System.Net.WebClient
            ...put the reading in NameValueCollection and upload to server page
            req = new NameValueCollection
            ...
            ...
            client.UploadValuesAsync(uri, "POST", req)
        endif
        thread.sleep(1) 'without this line the CPU usage goes upto 100% and seems to slow other tasks!
    Loop

当我运行程序时,我发现每次调用UploadValuesAsync时,调试窗口的打印都会停止。我还添加了调试语句以查看队列中有多少读数。如果这个任务确实是以低优先级运行的,我希望看到队列计数随着数据的获取而迅速增加,只有在前台空闲且不获取数据时才会减少。但事实并非如此。一旦将读数添加到队列中,它就会被出队并上传。因此,队列计数始终为1或0!
我的方法有问题吗?我是否根本不应该使用后台工作器对象?
顺便说一下,这是在运行Windows XP的双核笔记本电脑上进行的。
4个回答

17

补充一下Jon和Marc已经说过的:

后台线程并不具有更低的优先级。前台线程和后台线程之间的区别在于,CLR会在没有前台线程运行时关闭进程。线程池线程是后台线程。

实际上,您可以设置线程池线程的优先级,但由于您无法控制哪个线程池线程将实际运行您的任务,因此不建议这样做。如果您需要特定优先级的线程,应使用Thread类型创建它们,并根据需要设置实例的优先级。


1
为什么我不能将所有回复都标记为有帮助的?它们每一个都有一些有用的建议...! - Soundar Rajan
2
您只能选择一个答案,但您可以为所有有帮助的答案投票。 - Brian Rasmussen

8
是的,你的方法有问题——当队列为空时,你基本上是在进行紧密循环。无论线程优先级如何,这都是一个不好的想法。
使用后台工作者并没有什么问题,但是入队/出队应该真正使用一个生产者/消费者队列,当你尝试在没有准备好的情况下出队时,它会阻塞。
我在我的线程教程中有一个生产者/消费者队列的示例实现,可以查看链接页面的中间部分。(链接)顺便说一句,你需要一些方法来告诉出队过程已经完成,例如,入队一个null引用或其他特殊值。那段代码是在泛型出现之前编写的,但应该很容易更新。

在你的示例中,你期望队列中有10个项目,并且当消费者线程出队10个项目时终止。而在我的情况下,项目会在整个应用程序生命周期中添加到队列中(大约每秒钟添加10个项目),因此oWork不应该终止。除了紧密循环之外,还能做什么呢? - Soundar Rajan
@Soundar:唯一的区别在于终止条件。正如我在答案中建议的那样,您可以使用特殊值(例如 null)来表示终止 - 或者永远不终止。重要的是在没有条目时阻塞(而不是循环)。 - Jon Skeet
谢谢。在进一步阅读您的教程后,我现在知道我做错了什么。我应该使用Monitor.sleep而不是thread.sleep(我一直在想为什么我需要那个)。而monitor.wait似乎可以在DoWork函数内工作。 - Soundar Rajan
1
抱歉,我在上面的注释中想写“使用Monitor.Wait而不是Thread.sleep”。 - Soundar Rajan
1
是的 - Monitor.Wait 是关键点,尽管你不能仅仅替换当前对 Thread.Sleep 的调用 - 你需要在锁定状态下调用它。 - Jon Skeet

3
它并不声称是低优先级 - 后台意味着a: 不是UI线程,b: 它不会保持进程活动。实际上,它可能与ThreadPool线程有关。
如果您想要特定优先级的线程,则使用自己的Thread对象-但通常我甚至不建议这样做...
此外,“background”并不意味着“空闲时”。即使在单核机器上,您也可能会看到两个线程都获得尽可能多的运行时间(如果它们需要)。在多核上更是如此。

问题在于当后台线程调用UploadAsync时,似乎会阻塞/减慢UI线程。我可以看出这一点,因为上传发生时调试语句会暂停。我该如何避免这种情况? - Soundar Rajan
这是一台带有Win XP的双核笔记本电脑。 - Soundar Rajan

1

2
链接已损坏。 - ToolmakerSteve

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接