2014-11-12 3 views
0

Так что я пытаюсь заполнить большое количество значков списком. Чтобы избежать длительного времени ожидания, я пытаюсь загрузить его, чтобы загрузить первые 1000 результатов, а затем загрузить больше, если пользователь нажимает кнопку загрузки больше.Как ускорить добавление изображений в ImageList?

Здесь я застрял. Если я загружаю все 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)); 
    }); 
} 
+0

Не уверен, что это имеет смысл в вашем приложении, но, возможно, вы можете использовать более одного ImageList? Может быть, один для статеров и другой, чтобы заполнить остальное, пока пользователь все еще просматривает первую партию. Отправляйте 1ok в 10 ImageLists .. – TaW

+0

@JLYK поместите 'Image.FromFile (файл)' вне 'Invoke' блок. Ввод его в блок invoke приводит к тому, что он запускается в потоке графического интерфейса. – PoweredByOrange

+0

Такая же проблема, как String vs StringBuilder. Очень важно использовать метод Items.AddRange(). Поэтому ему не нужно постоянно перераспределять внутреннее хранилище. –

ответ

0

EDIT # 2: Дорогая часть функции загружает изображение из файла. Размещение перед блокировкой мьютекса должно допускать некоторый параллелизм, стоящий накладные расходы при использовании мьютекса. Нет, этот метод не сохраняет порядок. EDIT: добавление изображений непосредственно в список изображений, а не во временную коллекцию.

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(); 
    }); 
} 
+0

Это загружает изображения. Я боюсь, что это сильно повлияет на ресурсы GDI, в отличие от ImageList, который этого не делает. – TaW

+0

Итак, использование файлов. AsParallel() определенно помогло улучшить скорость. Загрузка всех результатов займет 27 секунд. Однако, когда я использовал Mutex, скорость вернулась до 37 секунд. Кроме того, есть ли способ сохранить порядок добавления изображений? – JLYK

+0

Это распространенная ошибка при использовании многопоточности. В этом случае первое, что происходит в теле цикла, - это блокировка мьютекса. Помимо того факта, что это почти то же самое, что и последовательный цикл, в этом случае есть также накладные расходы на блокировку объекта mutex, поэтому это может _potentially_ быть даже медленнее, чем обычный цикл. – PoweredByOrange

2

Чтобы ускорить любую насыпной операции, рассмотреть вопрос об использовании насыпного метода, если он доступен.
Например, тип 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.

+0

AddRange не может обрабатывать более 9000 изображений, но он отлично работает, если я сохраню цифры ниже этого. – JLYK

+0

@JLYK Затем попробуйте разделить свой большой «ImageList» на несколько маленьких. Кроме того, если вам нужен один и тот же набор изображений каждый раз, вы можете попытаться сериализовать 'ImageList' один раз и десериализовать его столько раз, сколько вам нужно. – Dmitry

+0

Я [узнал] (http://stackoverflow.com/questions/23084544/why-serializing-an-imagelist-doesnt-work-well), что легко сериализовать 'ImageList' с помощью свойства' ImageStream' , но его десериализировать очень сложно. Поэтому расщепление - единственный вариант, который я могу предложить. – Dmitry

Смежные вопросы