【问题标题】:How to speed up adding images to ImageList?如何加快向 ImageList 添加图像的速度?
【发布时间】:2015-01-09 23:06:45
【问题描述】:

所以我试图将大量图标填充到列表视图中。为了避免长时间的等待,我试图让它加载前 1000 个结果,然后在用户按下加载更多按钮时加载更多。

这就是我卡住的地方。如果我一次加载所有 10,000 多个图标,我需要 37 秒。但是,如果我决定每次用户单击按钮时再添加 500 个图标,我需要 40 秒,这比一次添加所有图标更糟糕!代码的唯一区别是我必须将这一行设为委托以避免跨线程问题。有没有更快的方法来做到这一点?

for (int i = lastLoadedIndex; i < lastLoadedIndex+500; i++)
{
    string file = resultArr[i];

    Invoke((MethodInvoker)delegate()
    {
        this.imageList1.Images.Add(Image.FromFile(file));
    });
}

【问题讨论】:

  • 不确定它在您的应用程序中是否有意义,但也许您可以使用多个 ImageList?也许一个用于状态者,另一个用于在用户仍在查看第一批时填充其余部分.. Ot 将 1ok 分成 10 个 ImageLists..
  • @JLYK 将Image.FromFile(file) 放在Invoke 块之外。将它放在调用块中会使其在 GUI 线程上运行。
  • 与 String 与 StringBuilder 的问题相同。使用它的 Items.AddRange() 方法非常重要。因此它不必经常重新分配其内部存储空间。

标签: c# winforms listview imagelist


【解决方案1】:

要加快任何 bulk 操作,请考虑使用 bulk 方法(如果可用)。
例如,ImageCollection 类型具有 AddRange 方法。
尝试使用它:

int newCount = 500;

// Get a desired part of the `resultArr` array as a new array:
string[] tmp = new string[newCount];
Array.Copy(resultArr, lastLoadedIndex, tmp, 0, newCount);

// Load images:
Image[] images = Array.ConvertAll(tmp, file => Image.FromFile(file));

// Bulk add images to the ImageList:
Invoke((MethodInvoker)(() => imageList1.Images.AddRange(images)));

如果没有帮助,请检查哪个操作慢:读取图像或附加到ImageList

【讨论】:

  • AddRange 似乎无法处理超过 9000 张以上的图像,但如果我将数字保持在低于该值的范围内,它的效果会很好。
  • @JLYK 然后尝试将你的大ImageList 分成几个小的。此外,如果您每次都需要相同的一组图像,您可以尝试将ImageList 序列化一次,然后根据需要多次反序列化。
  • 我已经found out 表示,通过其ImageStream 属性序列化ImageList 很容易,但反序列化却非常困难。所以分裂是我能建议的唯一选择。
  • 到目前为止,拆分大 ImageList 似乎对我有用。但是每次更新后,我都会失去在列表视图中的位置,最终选择了一个我最初不想点击的图标。知道如何使 ImageList 更新更加无缝?
  • 在我的测试中,ImageList.AddRange 并不比使用 .Add 的循环快。它们的性能几乎相同。
【解决方案2】:

编辑#2:函数的昂贵部分是从文件中加载图像。在锁定互斥锁之前放置它应该允许一些并行性,值得使用互斥锁的开销。不,此方法不保留顺序。 编辑:将图像直接添加到图像列表而不是临时集合。

public void LoadImagesFromFiles(string[] files)
{
    Mutex imageListLock = new Mutex();
    files.AsParallel().ForAll(file =>
    {
        var img = Image.FromFile(file);
        imageListLock.WaitOne();
        this.imageList1.Images.Add(img);
        imageListLock.ReleaseMutex();
    });
}

【讨论】:

  • 这会加载图像。恐怕它会对 GDI 资源造成沉重负担,而 ImageList 不会这样做。
  • 所以使用 files.AsParallel() 肯定有助于提高速度。现在加载所有结果需要 27 秒。然而,当我使用 Mutex 时,速度又回到了 37 秒。另外,有没有办法保留添加图像的顺序?
  • 这是使用多线程时的常见错误。在这种情况下,循环体中发生的第一件事就是锁定互斥体。除了这与顺序循环几乎相同的事实之外,在这种情况下,还存在锁定互斥对象的开销,因此这可能可能比常规 for 循环还要慢。
猜你喜欢
  • 1970-01-01
  • 2016-11-20
  • 1970-01-01
  • 1970-01-01
  • 2015-01-21
  • 2021-09-22
  • 2020-02-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多