Хорошо, я написал функцию, которая будет выполнять работу, распределенную по нескольким потокам, а затем обнаружил «ошибку» в моем коде.(Тем не менее, использование многопоточности очень помогает, поэтому image.fromFile
явно узкое место для процессора, а не для (локального) SSD).
1.) Загрузка по сети
В коде, указанном выше: System.IO.FileInfo[] files2 = di.EnumerateFiles("*.jpg", SearchOption.AllDirectories).ToArray();
- я использовал для перечисления di
вместо di2
(di
относится к общему сетевому ресурсу)
(таким образом Array.ConvertAll
обращался к удаленным файлам)
Время выполнения «такого» подхода: 6 с 414 мс
2.) Локальная загрузка
Фиксация этого вывода на время выполнения 1 с 886 мс
3.) Локальная резьба-Загрузка
Тем не менее, моя ThreadedLoading
-функция уже была выполнена, поэтому я тоже попробовал:
0s 543ms - так еще почти 4 разабыстрее на 8-ядерном с 4-мя физическими ядрами.
Вот код.Может еще не быть пуленепробиваемым, но дает надежные и быстрые (est) результаты
использование:
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
В соответствии с рекомендациями Фелипе РамосаЯ попробовал 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");