使用大量项目(1,000或更多)迭代集合并实时更新项目属性的最有效方法是什么?目前,我的程序使用WriteableBitmap
在画布上为集合中的每个对象绘制一个图像(虽然我看不出它与简单的椭圆之间的性能有任何差异)并将其移动到屏幕上。我试图暂时保持逻辑尽可能简单。
<UserControl.Resources>
<DataTemplate DataType="{x:Type local:Entity}">
<Canvas>
<Image Canvas.Left="{Binding Location.X}"
Canvas.Top="{Binding Location.Y}"
Width="{Binding Width}"
Height="{Binding Height}"
Source="{Binding Image}" />
</Canvas>
</DataTemplate>
</UserControl.Resources>
<Canvas x:Name="content"
Width="2000"
Height="2000"
Background="LightGreen">
<ItemsControl Canvas.ZIndex="2" ItemsSource="{Binding Entities}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
[Magic]
public class Entity : ObservableObject
{
public Entity()
{
Height = 16;
Width = 16;
Location = new Vector(Global.rand.Next(800), Global.rand.Next(800));
Image = Global.LoadBitmap("Resources/Thing1.png");
}
public int Height { get; set; }
public int Width { get; set; }
public Vector Location { get; set; }
public WriteableBitmap Image { get; set; }
}
(在上面的Entity类中,[Magic]属性在我的所有属性上实现了INPC)
我尝试使用System.Timers.Timer
,System.Threading.Timer
和System.Threading.DispatcherTimer
来创建具有不同间隔的循环。一切都表现得相当好,直到我到达集合中的大约800个对象,然后它们开始变得不连贯。我也尝试使用标准foreach
循环和Parallel.ForEach
循环,并没有真正注意到两者之间的差异。我的循环有更复杂的逻辑,但我已经尽可能简单,直到我弄清楚如何简化流程:
void Timer_Tick(object sender, EventArgs e)
{
Parallel.ForEach(Entities, entity =>
{
entity.Location = new Vector(entity.Location.X + 1, entity.Location.Y);
});
}
(另外,这不是Canvas的问题;如果我绘制10个项目并且在没有图像的情况下生成1,000个,它仍会变得不稳定。)
如何让我的程序更有效地实时处理大型集合?我猜我有一点点失踪,因为这是我第一次处理这种性质的事情。任何建议都将不胜感激。
答案 0 :(得分:2)
收藏品最好以每个帖子一次处理,但有一些选项:
如果任何进程需要一些长时间且非完全消耗的CPU操作,您将在问题中使用您的方法,即每个操作的线程。
如果有大量具有较少流程操作时间的集合,您可能最好只使用一个主题。
如果在线程之间进行同步,则还会对性能产生影响。如果你经常这样做,那可能会降低速度。
在任何情况下,总会有一个思考和强制的地方 - 用于处理行动的基准不同方法。后一个选项将帮助您了解多任务工作流程。
对于一些轻量级的arythmetic CPU绑定操作,您可以随意使用 a 线程。
List<List<Action>> actions = InitializeActions();
foreach(var list in actions)
{
var listCopy = list; // Mandatory where execution is deferred.
// Each collection is stared on different thread from thread pool.
Task.Factory.StartNew(() =>
{
foreach(var action in listCopy)
{
action();
}
}
}
// Single thread executes all the code.
List<List<Action>> actions = InitializeActions();
foreach(var list in actions)
{
foreach(var action in listCopy)
{
action();
}
}
List<List<Action>> actions = InitializeActions();
foreach(var list in actions)
{
foreach(var action in listCopy)
{
// Spawn a thread on each action.
Task.Factory.StartNew(action);
}
}
这当然非常简单粗暴,但你明白了。