Оптимизация алгоритма - параллельные AsyncTasks или потоки?

В настоящее время у меня есть один AsyncTask, который в настоящее время сравнивает изображения с использованием метода bubble sort с использованием OpenCV. Скажем, мне нужно сравнить 400 изображений друг с другом. Это будет означать 400*401/2=80,200 сравнения. Предположим, что одно сравнение занимает 1 секунду. Итак, это 80,200 sec, что примерно равно 22.27 hours, что смехотворно долго. Итак, я разработал алгоритм такого типа:

Он делит 400 изображений на группы по 5. Итак, в каждой группе 80 изображений.

Первая часть алгоритма — изображения, сравнивающие себя внутри членов группы.

Итак, image1 будет сравнивать себя с image2-80, а это значит, что имеется 79 сравнений. image2 будет иметь 78 сравнений и так далее. Что делает 3,160 сравнений. Или 3,160 sec. Точно так же image81 будет сравнивать себя с image82-160 и так далее. Таким образом, все «групповые сравнения» завершаются в 3,160 sec, потому что они выполняются параллельно.

Вторая часть алгоритма будет сравнивать group 1 элементов с group 2 элементами, group 2 с group 3, group 3 с group 4 и так далее. Это будет означать, что image1 будет сравниваться с image81-160, что составляет 80 сравнений, и поэтому общее количество сравнений между group 1 и group 2 будет 80*80=6400 сравнениями. Можно ли сравнивать каждое изображение параллельно с групповым сравнением? То есть, если image1 сравнивает себя с image81-160, то image2 должен делать то же самое и так далее, в то время как другие группы делают то же самое. Итак, эта часть должна занимать всего 6400 sec.

Теперь group1 будет сравниваться с group3, group2 с group4, group3 с group5. ->6400 sec

После чего group1 will be compared with group4 и group2 с group5. ->6400 sec

Итак, все группы сравниваются.

Общее время = 3160+6400+6400+6400=22,360sec. Я понимаю, что чем больше групп, тем больше времени это займет. Итак, мне пришлось бы увеличить размер группы, чтобы уменьшить увеличение времени. В любом случае, это сокращает время почти до 1/4th реального времени.

Является ли этот алгоритм нереалистичным? Если да, то почему? Какие у него недостатки? Как бы я это исправить? Есть ли лучший алгоритм для более быстрого сравнения списка изображений? Явно не quick sort, я не могу расположить изображения в порядке возрастания или убывания. Или я могу?

Возможен ли этот алгоритм? Каков был бы лучший способ реализовать это? Thread или AsyncTask?


person Karthik Balakrishnan    schedule 23.04.2013    source источник
comment
хорошо, я могу сказать вам, что вы должны использовать объекты Thread для этих операций. Объекты AsyncTask используются для операций длительностью не более нескольких секунд.   -  person Joel    schedule 23.04.2013
comment
Что означает сравнение изображений? Вычисляет ли он какой-либо общий порядок, частичный порядок или просто сходство?   -  person Alexei Kaigorodov    schedule 23.04.2013
comment
@Joel Не могли бы вы показать мне пример примерно с 20 изображениями?   -  person Karthik Balakrishnan    schedule 23.04.2013
comment
@AlexeiKaigorodov - Сходство с использованием метода FREAK.   -  person Karthik Balakrishnan    schedule 23.04.2013
comment
Сравнение на предмет (не)равенства лучше всего проводить на изображениях уменьшенного размера. Вы можете строго масштабировать изображения до 32x32. Для Android лучшее решение, да и уменьшение масштаба само по себе может быть быстрым. Возможно, сначала проверьте пару случайных пикселей.   -  person Joop Eggen    schedule 23.04.2013
comment
Изображения 32x32 не имеют ключевых точек. Сравнение будет основано на контрольных суммах хэшей. Это очень неточно. Если два похожих изображения имеют разную контрольную сумму и уменьшены в масштабе, они не будут распознаны как дубликаты.   -  person Karthik Balakrishnan    schedule 24.04.2013


Ответы (1)


Это реалистичный алгоритм, но в идеале вы должны иметь возможность использовать одинаковое количество рабочих потоков во всей программе. Для этого вам нужно использовать четное количество потоков, скажем, 8.

На Pass1 Thread1 обрабатывает изображения 1–50, Thread2 обрабатывает изображения 51–100 и т. д.

На Pass2 потоки Thread1 и Thread2 обрабатывают изображения 1–100. Thread1 обрабатывает изображения 1–25 и 50–75, Thread2 обрабатывает изображения 26–50 и изображения 76–100. Затем Thread1 обрабатывает изображения 1–25 и 76–100, а Thread2 обрабатывает изображения 26–75.

Проходы с 3 по 8 выполняются по той же схеме — два потока, назначенные двум обрабатываемым группам, разделяют группы между собой. Таким образом, вы держите все свои потоки занятыми. Однако для этого вам понадобится четное число потоков, чтобы упростить разделение групп.

Пример кода для 4 потоков

class ImageGroup {
    final int index1;
    final int index2;
}

class ImageComparer implements Runnable {
    final Image[] images;
    ImageGroup group1;
    ImageGroup group2;

    public ImageComparer(Image[] images, ImageGroup group1, ImageGroup group2) {
        ...
    }

    public void run() {
        if(group2 == null) { // Compare images within a single group
            for(int i = group1.index1; i < group1.index2; i++) {
                for(int j = i + 1; j < group1.inex2; j++) {
                    compare(images[i], images[j]);
                }
            }
        } else { // Compare images between two groups
            for(int i = group1.index1; i < group1.index2; i++) {
                for(int j = group2.index1; j < group2.index2; j++) {
                    compare(images[i], images[j]);
                }
            }
        }
    }
}

ExecutorService executor = new ThreadPoolExecutor(); // use a corePoolSize equal to the number of target threads
// for 4 threads we need 8 image groups
ImageGroup group1 = new ImageGroup(0, 50);
ImageGroup group2 = new ImageGroup(50, 100);
...
ImageGroup group8 = new ImageGroup(450, 500);

ImageComparer comparer1 = new ImageComparer(images, group1, null);
ImageComparer comparer2 = new ImageComparer(images, group3, null);
...
ImageComparer comparer4 = new ImageComparer(images, group7, null);

// submit comparers to executor service
Future future1 = executor.submit(comparer1);
Future future2 = executor.submit(comparer2);
Future future3 = executor.submit(comparer3);
Future future4 = executor.submit(comparer4);

// wait for threads to finish
future1.get();
future2.get();
future3.get();
future4.get();

comparer1 = new ImageComparer(images, group2, null);
...
comparer4 = new ImageComparer(images, group8, null);

// submit to executor, wait to finish

comparer1 = new ImageComparer(images, group1, group3);
...
comparer4 = new ImageComparer(images, group7, group6);

// submit to executor, wait to finish

comparer1 = new ImageComparer(images, group1, group4);
...
comparer4 = new ImageComparer(images, group7, group5);
person Zim-Zam O'Pootertoot    schedule 23.04.2013
comment
Кроме того, разве на 2 потока меньше? Я планировал иметь 4 потока, каждый из которых выполнял свой собственный набор сравнений для каждого прохода параллельно с другими потоками. - person Karthik Balakrishnan; 23.04.2013
comment
Извините за путаницу, я описывал только выполнение 2 из 8 потоков. Я добавил в свой ответ пример кода, как разделить изображения на 4 потока. - person Zim-Zam O'Pootertoot; 23.04.2013