我遵循了本教程,创建了一个优先级队列,并使用一个阻塞集合包装它。我有一个DataGrid,它连接到底层优先级队列,它会发出更改事件。我可以从UI线程w/out中将项添加到集合中,当缓冲区如预期的那样满时,它会阻塞。
现在我如何消费这些物品?我要说的是:
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个消费者,并让他们并行运行。
这该怎么做?
发布于 2010-10-19 21:25:28
包装CollectionChanged
事件w/ a调度器似乎很好.
public bool TryAdd(KeyValuePair<int, T> item)
{
int pos = _queues.Take(item.Key + 1).Sum(q => q.Count);
_queues[item.Key].Enqueue(item.Value);
Interlocked.Increment(ref _count);
Dispatcher.BeginInvoke(
new Action(
() =>
NotifyCollectionChanged(
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, pos))
));
return true;
}
我的ConcurrentPriorityQueue
只需要从DispatcherObject
那里得到。我想这就是该怎么做的。
更简单的是,只需编写如下的NotifyCollectionChanged
方法:
private void NotifyCollectionChanged(NotifyCollectionChangedEventArgs e)
{
lock (CollectionChanged)
{
if (CollectionChanged != null)
Dispatcher.BeginInvoke(new Action(() => CollectionChanged(this, e)));
}
}
然后你就不用用BeginInvoke
乱扔你的其他方法了。
发布于 2010-10-20 00:26:32
在就这个问题发表意见之后,
您不需要“使用UI线程获取项目”。但是,在处理消费任务中的项目时,对UI的任何更新都需要分派到UI线程。把你们的顾虑分开!
https://stackoverflow.com/questions/3972273
复制相似问题