为了保持性能“高”,当使用我们的应用程序时,我们对所有的列表视图使用(预加载的)图像列表。
biggeset listview可以包含大约9000张图像的imagelist。
因此,为了生成图像列表,我们使用了addRange(),它可以在几乎没有时间的情况下完成这项工作。
但是,在启动期间,将映像从文件系统“加载”到image[]数组仍然需要4-5秒。(约80 MB,在固态硬盘上)
我想知道是否有更好的方法从(本地)文件系统中填充“大”图像列表?
目前我们使用的是:
System.IO.DirectoryInfo di2 = new System.IO.DirectoryInfo(Config.ProductImageLocalPath);
System.IO.FileInfo[] files2 = di.EnumerateFiles("*.jpg", SearchOption.AllDirectories).ToArray();
int idx = 1; //0 is reservevd for default image, which is already added.
foreach (FileInfo fi in files2)
{
Resources.ImageIndex.Add(long.Parse(Path.GetFileNameWithoutExtension(fi.Name)), idx++);
}
Image[] images = Array.ConvertAll(files2, file => Image.FromFile(file.FullName));
Resources.ProductImageList_256.Images.AddRange(images);ImageIndex只是一个dictionary<Long, int>,它允许将实际的id (从文件名派生)映射到相应图像映射中的从0开始的索引,并且不需要任何时间来生成。
显然,Image[] images = Array.ConvertAll(files2, file => Image.FromFile(file.FullName));是瓶颈,因为这相当于对Image.fromFile的9000次调用(是否也有一些批量选项?)。
这里有什么“更好”的点子吗?
发布于 2018-10-09 02:51:55
好吧,所以我写了一个函数,它将完成分配给几个线程的工作-然后在我的代码中发现了一个"bug“。(然而,使用多线程也有很大帮助,所以image.fromFile的瓶颈显然是中央处理器,而不是(本地)固态硬盘)。
1。)网络加载
在上面提到的代码中:System.IO.FileInfo[] files2 = di.EnumerateFiles("*.jpg", SearchOption.AllDirectories).ToArray(); -I使用di而不是di2进行枚举(di指的是网络共享)
(所以Array.ConvertAll正在访问远程文件)
“此”方法的运行时:6s 414ms
2。)本地加载
修复导致1s 886ms运行时出现的问题
3。)本地线程加载
但是,我的ThreadedLoading-Function已经完成了,所以我也尝试了一下:
0s 543ms -所以在有4个物理核心的8核上仍然要快4倍。
这是代码。可能还不是防弹的,但会产生可靠且快速的(估计)结果。
用法:
DateTime t1 = DateTime.Now;
//Image[] images = Array.ConvertAll(files2, file => Image.FromFile(file.FullName));
Image[] images = loadImagesThreaded(files2);
DateTime t2 = DateTime.Now;
TimeSpan ts = t2.Subtract(t1);
MessageBox.Show("Loading took: " + ts.Seconds + "s " + ts.Milliseconds + "ms"); //6s 414ms
Resources.ProductImageList_256.Images.AddRange(images);功能:
private Image[] loadImagesThreaded(FileInfo[] files)
{
int threadCount = 8;
int chunkSize = files.Length / threadCount; //Round about - doesn't need to be precise.
Thread[] threads = new Thread[threadCount];
Image[][] result = new Image[threadCount][];
for (int i = 0; i < threadCount; i++)
{
FileInfo[] chunk;
int lowerBound = i * chunkSize;
if (i < threadCount - 1)
{
chunk = files.Skip(lowerBound).Take(chunkSize).ToArray();
}
else
{
//take the rest
chunk = files.Skip(lowerBound).ToArray();
}
int j = i;
threads[i] = new Thread(() =>
{
result[j] = Array.ConvertAll(chunk, file => Image.FromFile(file.FullName));
});
threads[i].Start();
}
//wait for threads to finish.
Boolean oneAlive = true;
while (oneAlive)
{
oneAlive = false;
foreach (Thread t in threads)
{
if (t.IsAlive)
{
oneAlive = true;
break;
}
}
}
//all done.
Image[] finalResult = new Image[files.Count()];
for (int i = 0; i < threadCount; i++)
{
int lowerBound = i * chunkSize;
result[i].CopyTo(finalResult, lowerBound);
}
return finalResult;
}这不是一个很好的峰值吗,同时预加载图像?:-)

4。)Parallel.ForEach
根据Felipe Ramos的推荐,我尝试了Parallel.ForEach。它比我的“线程化”解决方案快了大约40-50毫秒(主要是480-500毫秒)--但也许更重要的事实是:
这是不需要动脑筋的,因此更可靠,我要说:
Image[] images = new Image[files2.Count()];
Parallel.ForEach(files2, (fileInfo, state, index) =>
{
images[index] = Image.FromFile(fileInfo.FullName);
});
DateTime t2 = DateTime.Now;
TimeSpan ts = t2.Subtract(t1);
MessageBox.Show("Loading took: " + ts.Seconds + "s " + ts.Milliseconds + "ms");https://stackoverflow.com/questions/52707427
复制相似问题