【发布时间】:2010-10-19 20:06:36
【问题描述】:
我已经关注this tutorial,创建了一个优先队列并用阻塞集合包装了它。我有一个 DataGrid,我已将其连接到发出更改事件的底层优先级队列。我可以从 UI 线程将项目添加到集合中,而不会出现故障,并且当缓冲区已满时它会阻塞。
现在我该如何消费这些物品?这是我得到的:
public DownloadViewModel()
{
Queue = new ConcurrentPriorityQueue<DownloadItem>(10);
Buffer = new BlockingCollection<KeyValuePair<int, DownloadItem>>(Queue, 10000);
Task.Factory.StartNew(() =>
{
KeyValuePair<int, DownloadItem> item;
while(!Buffer.IsCompleted)
{
if(Buffer.TryTake(out item))
{
// do something with the item
}
Thread.SpinWait(100000);
}
});
}
但是,一旦我添加了 Task.Factory.StartNew 位,我的应用程序突然需要 30 秒才能出现窗口(在它是即时之前),当我添加一个项目时,我得到了异常
这种类型的 CollectionView 不支持从不同于 Dispatcher 线程的线程更改其 SourceCollection。
我理解,但真的有必要使用 UI 线程获取项目吗?这不是破坏了使用这个 BlockingCollection 的全部目的吗?我想创建 4 或 8 个消费者并让它们并行运行。
这应该怎么做?
【问题讨论】:
-
真的只需要从 UI 线程更新 UI 控件。这就是异常告诉你的。是的,这很快就破坏了精心设计的线程方案的用处。
-
@Hans:当然,但是当阻塞队列尝试获取一个项目时,底层队列会发出一个更改通知,.. 为什么不能自动委托回 UI 线程?为什么要阻止消费者?无论如何..我现在愿意接受任何解决方案,即使它的效率比我认为的要低一些。我想这是一个非常普遍的范例。生产者-消费者并不是什么新鲜事,向用户显示剩余的项目应该不难吗?
-
在线程方面没有什么是自动或简单的。在列表中收集结果并使用 Dispatcher.BeginInvoke 更新 UI。
-
消费者不应该被阻止......消费者应该消费这些物品,并且做他们所做的任何事情(下载一个项目?)并且这些项目的消费对UI造成的任何变化都应该从消费者发送到 UI。在 UI 线程上生产和消费会有点傻——这肯定会破坏多线程的整个目的吗? (没有时间关注这篇文章或制作一个工作示例,所以恐怕不是一个完整的答案)
-
@Giraffe:是的,这正是我想说的。消费者不应该因为等待更新 UI 而成为瓶颈。
标签: c# wpf concurrency