首页 > 解决方案 > 随后将任务添加到任务中,但限制并行执行的数量

问题描述

当我想在包含超过 10k 个条目的网格中显示缩略图时,我遇到了严重的性能问题,即 100% 运行四个内核,阻塞了其他所有内容。
当向用户显示一行时会触发一个事件,该事件会加载图像。在这种情况下,GridImageManager使用 调用的实例AddAndStartLoading。当我向下滚动时,这个事件被触发得太频繁了,我的核心被线程淹没了。

我试图重写代码,使用回调和仍然加载单元的列表,但该列表不是线程安全的,导致异常,当我想删除一个已经从另一个线程中删除的元素时。

然后我尝试使用信号量,但使用它们我无法实现WaitForLoadingCompleted- 方法,因为我无法访问大量空闲资源。

我也阅读了 Tasks,但不知道它们将如何帮助我。

我的限制如下:

我必须使用哪些模式/策略来完成此任务?

给你一个想法:这是我的第一次尝试。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
        }
    }
}

标签: c#multithreadingwinformsasync-await

解决方案


推荐阅读