我遇到严重的性能问题,即当我想在包含超过1万个条目的网格中显示缩略图时,四个内核以100%的速度运行,从而阻塞了其他所有内容。
当向用户显示一条线时会触发一个事件,该事件会加载图像。在这种情况下,GridImageManager
的实例将被AddAndStartLoading
调用。当我向下滚动时,此事件触发得太多,并且我的核心被线程淹没。
我尝试使用回调和仍然要加载的单元的列表来重写代码,但是该列表不是线程安全的,导致异常,当我想删除一个已经从另一个线程中删除的元素时。 / p>
然后,我尝试使用信号量,但是有了它们,我无法实现WaitForLoadingCompleted
方法,因为我无法访问大量的可用资源。
我也读过Tasks,但无法了解它们如何帮助我。
我的约束如下:
AddAndStartLoading
之后,必须立即开始加载图像。N
个加载过程。AddAndStartLoading
的调用可能会等待,但是一旦加载进程的数量降到N
以下,就应该处理。WaitForLoadingCompleted
应该等待所有的加载线程完成,而另一方面允许执行Application.DoEvents()
。我目前无法重构。我必须使用什么模式/策略来实现这一目标?
给您一个想法:这是我的第一次尝试。直到CellsToLoad
变空为止。
public class GridImageManager
{
public GridImageManager()
{
CellsToLoad = new List<(UltraGridCell cell, ImageLoader loader)>();
LoadingCells = new Dictionary<UltraGridCell, ImageLoader>();
}
public delegate void ImageLoader(object obj);
private List<(UltraGridCell cell, ImageLoader loader)> CellsToLoad { get; set; }
private Dictionary<UltraGridCell, ImageLoader> LoadingCells { get; set; }
public void AddCellToLoad(UltraGridCell cell, ImageLoader loader)
{
CellsToLoad.Add((cell, loader));
StartLoading();
}
private void CallbackImageLoaded(IAsyncResult ar)
{
if (ar.AsyncState is UltraGridCell cell)
{
LoadingCells.Remove(cell);
StartLoading();
}
}
private void StartLoading()
{
if (LoadingCells.Count >= 10)
return;
if (CellsToLoad.Count == 0)
return;
var next = CellsToLoad.First();
CellsToLoad.Remove(next);
LoadingCells.Add(next.cell, next.loader);
next.loader.BeginInvoke(null, CallbackImageLoaded, next.cell);
}
public void WaitForLoadingCompleted()
{
while (CellsToLoad.Count > 0 && LoadingCells.Count > 0)
{
Application.DoEvents(); // Can't refactor this right now
}
}
}