ThreadPool 适合这种线程场景吗?
我有一个场景,如果可能的话,我试图在用户实际需要结果之前预先获取结果的一些子元素,从而将其变成响应速度更快的 UI。我不清楚如何最好地处理线程,所以我希望有人可以提供一些建议。
场景
有一个搜索表单(.NET 富客户端),使用户能够为给定客户选择帐户。用户搜索给定文本以查找客户集合,然后将其显示在结果网格中。然后,当用户选择客户时,系统会搜索该客户的帐户列表并将其显示在第二个网格中以供用户选择,以构成要打开的最终上下文(即帐户)。
现有系统
我将这一切都以请求/响应方式运行,使用常规后台线程分别解析客户和客户帐户,直接响应用户选择。 UI 被锁定/禁用(但响应),直到找到帐户。
目标
我想要实现的是在用户选择前 N 个客户之前开始获取他们的帐户...其中 N 是网格中显示的项目数。
当用户滚动网格时,新显示的项目将被添加到要获取的“队列”中。
问题
- 线程池是管理线程的合适机制吗?如果是这样,您可以强制只让一个排队的工作项优先级上升吗? - 例如,如果用户在开始/完成获取之前选择该客户。
- 如果没有,我还应该做什么?
- 无论哪种方式,您是否知道任何展示此功能的优秀博客文章和/或开源项目?
I have a scenario that I'm trying to turn into a more responsive UI by pre-fetching some sub-elements of the results before they're actually required by the user if possible. I'm unclear on how best to approach the threading, so I'm hoping someone can provide some advice.
Scenario
There is search form (.NET rich client) that enable the user to select an account for a given customer. The user searches for given text to find a collection of customers which are then displayed in a result grid. Then when the user selects a customer, the list of accounts for that customer are searched for and displayed in a second grid for user selection in order to make up the final context (that is an account) to open.
Existing System
I have this all running in a request/response manner using regular background threading to resolve customers and accounts for a customer respectively in direct response to the user selections. The UI is locked/disabled (but responsive) until the accounts are found.
Goal
What I want to achieve is to commence fetching of the accounts for the top N customers before the user has selected them... Where N is the number of items being displayed in the grid.
As the user scrolls the grid, the newly displayed items will be added to the "queue" to be fetched.
Questions
- Is the thread pool an appropriate mechanism for managing the threads? If so, can you force just a single queued work item to jump up in priority? - e.g. if the user selects that customer before they have started/finished fetching.
- If not, what else should I be doing?
- Either way, are you aware of any good blog posts and/or open source projects that exhibit this functionality?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
是的,线程池是一个不错的选择,可能位于Backgroundworker 或.NET4 的TaskParallel 库后面。
但是你不能(不应该)“碰撞”ThreadPool 线程,但我认为这无论如何都不会有用。
您可能应该做的是使用线程安全队列(前 N 个项目)并使用 2 个以上线程来处理队列。当选择一个项目但尚未处理时,您可以将其向上移动或立即启动一个单独的线程。
Yes, the threadpool is a good choice, maybe behind a Backgroundworker or .NET4's TaskParallel library.
But you cannot (should not) 'bump' a ThreadPool thread but I don't think that is going to be useful anyway.
What you should probably do is to use a thread-safe queue (of the top N items) and use 2+ threads to process the Queue. When an item is selected and not yet being processed you move it up or start a separate thread immediately.
通过更新/解决方案...我遵循了 Henk 的< /a> 解决方案(某种程度上),这样我保留了工作项对象的队列,但仍然使用线程池处理它们。选定的项目通过将它们放在队列的前面(而不是后面)来“碰撞”[注意:为此需要一个特殊的集合]。
下面可能会详细描述它(代替代码)
Customer
以保留名为 KnownValues 的IList
属性以及一个用于锁定名为 KnownValuesSyncObject 的对象(因为我希望 KnownValues 在未知时为空)。Deque
(来自 PowerCollections)ManualResetEvent
句柄。ThreadPool.QueueUserWorkItem
调用的上下文/状态是我的 _accountLoadingWorkItems 队列。Customer.KnownValues
尚未填充(即它可能位于队列中的某处),那么它已经是单独的线程(通过 BackgroundWorker),那么它将新的 CustomerAccountLoadingWorkItem 添加到工作项队列(但在顶部!!![这就是需要 Deque 的原因]),并向 ThreadPool 添加新的处理任务。然后,由于它创建了工作项,因此它调用ManaulResetEvent.WaitOne()
来强制等待线程池任务完成。我希望这是有道理的...
值得注意的是,由于当用户选择一个项目时我的解决方案仍然使用 ThreadPool,我仍然必须等待当前正在运行的线程池线程完成才能拾取我的工作项目,我认为这是可以的甚至可能希望看到用于查询帐户的资源(网络服务)将被半锁定,无论如何它可能会同样快速地出现(由于一些糟糕的架构和共享的网络服务代理)。
总的来说,我确实让原本简单的工作变得更加困难,如果我能够使用 Framework 4,我肯定会考虑走 TPL 路线。
By way of an update / solution... I followed Henk's solution (sort of) such that I keep a queue of work item objects but I still process them using the ThreadPool. Selected items are 'bumped' by putting them on the front of the queue (rather than the back) [note: needed a special collection for this].
The following might describe it in detail (in lieu of code)
Customer
to keep a property ofIList<Account>
named KnownValues and also an object used for locking named KnownValuesSyncObject (since I want the KnownValues to be null when they aren't yet known).Deque<CustomerAccountLoadingWorkItem>
(from PowerCollections)CustomerAccountLoadingWorkItem
maintains a reference to the Customer it's meant to process for, as well as it'sManualResetEvent
handle that it was created with.ThreadPool.QueueUserWorkItem
call was my _accountLoadingWorkItems queue.Customer.KnownValues
isn't already filled (i.e. it's probably sitting in the queue somewhere), then it adds a new CustomerAccountLoadingWorkItem to the work item queue (but at the top!!! [this was why the Deque was required]) and also adds a new processing task to the ThreadPool. Then since it created the work item it callsManaulResetEvent.WaitOne()
to force waiting for the thread pool task to complete.I hope that made sense...
Of note, since my solution still uses the ThreadPool when the user selects an item I still have to wait for currently running thread pool thread's to finish before my work item gets picked up, I figured that was OK and possibly even desirable seeing as though the resources used to query for the accounts (a webservice) will be semi-locked up it'll probably come up equivalently quick anyway (due to some poor architecting and a shared web service proxy).
Overall, I certainly made what should have been an easy-ish job somewhat more difficult and should I have been able to use Framework 4 I would have looked at going down the TPL route for sure.
如果 .NET 4 是一个选项,我可以推荐新的 ConcurrentStack 集合吗?
http://msdn.microsoft.com/en -us/library/dd267331(v=VS.100).aspx
您可以添加要预取的所有项目,如果用户选择了某个项目,您可以将该选择推送到堆栈上它是下一个要检索的实例。这与新的 PLINQ 和 TPL 配合得很好,并利用了 .NET 4 中新的 ThreadPool 改进。
http://channel9.msdn.com/shows/Going+Deep/Erika-Parsons-and-Eric-Eilebrecht- -CLR-4-新线程池内部/
If .NET 4 is an option, might I recommend the new ConcurrentStack collection.
http://msdn.microsoft.com/en-us/library/dd267331(v=VS.100).aspx
You can add all the items you want to pre-fetch and if an item is selected by the user, you can push that selection onto the stack making it the next instance to be retrieved. This works great with the new PLINQ and TPL and makes use of the new ThreadPool improvements in .NET 4.
http://channel9.msdn.com/shows/Going+Deep/Erika-Parsons-and-Eric-Eilebrecht--CLR-4-Inside-the-new-Threadpool/