Я пишу многопоточное приложение на Java, чтобы повысить производительность по сравнению с последовательной версией. Это параллельная версия решения динамического программирования для проблемы с рюкзаком 0/1. У меня есть Intel Core 2 Duo с Ubuntu и Windows 7 Professional на разных разделах. Я бегу в Ubuntu.
Моя проблема в том, что параллельная версия на самом деле занимает больше времени, чем последовательная версия. Я думаю, это может быть потому, что потоки все сопоставлены с одним и тем же потоком ядра или что они распределяются по одному ядру. Могу ли я гарантировать, что каждый поток Java сопоставляется с отдельным ядром?
Я прочитал другие сообщения об этой проблеме, но ничего не помогает.
Вот конец main() и все run() для класса KnapsackThread (который расширяет Thread). Обратите внимание, что они используют срез и дополнительные для вычисления myLowBound и myHiBound, чтобы каждый поток не перекрывался в домене dynProgMatrix. Поэтому не будет никаких условий гонки.
dynProgMatrix = new int[totalItems+1][capacity+1];
for (int w = 0; w<= capacity; w++)
dynProgMatrix[0][w] = 0;
for(int i=0; i<=totalItems; i++)
dynProgMatrix[i][0] = 0;
slice = Math.max(1,
(int) Math.floor((double)(dynProgMatrix[0].length)/threads.length));
extra = (dynProgMatrix[0].length) % threads.length;
barrier = new CyclicBarrier(threads.length);
for (int i = 0; i < threads.length; i++){
threads[i] = new KnapsackThread(Integer.toString(i));
}
for (int i = 0; i < threads.length; i++){
threads[i].start();
}
for (int i = 0; i < threads.length; i++){
try {
threads[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void run(){
int myRank = Integer.parseInt(this.getName());
int myLowBound;
int myHiBound;
if (myRank < extra){
myLowBound = myRank * (slice + 1);
myHiBound = myLowBound + slice;
}
else{
myLowBound = myRank * slice + extra;
myHiBound = myLowBound + slice - 1;
}
if(myHiBound > capacity){
myHiBound = capacity;
}
for(int i = 1; i <= totalItems; i++){
for (int w = myLowBound; w <= myHiBound; w++){
if (allItems[i].weight <= w){
if (allItems[i].profit + dynProgMatrix[i-1][w-allItems[i].weight]
> dynProgMatrix[i-1][w])
{
dynProgMatrix[i][w] = allItems[i].profit +
dynProgMatrix[i-1][w- allItems[i].weight];
}
else{
dynProgMatrix[i][w] = dynProgMatrix[i-1][w];
}
}
else{
dynProgMatrix[i][w] = dynProgMatrix[i-1][w];
}
}
// now place a barrier to sync up the threads
try {
barrier.await();
} catch (InterruptedException ex) {
ex.printStackTrace();
return;
} catch (BrokenBarrierException ex) {
ex.printStackTrace();
return;
}
}
}
Обновление:
Я написал еще одну версию рюкзака, который использует грубую силу. Эта версия имеет очень мало синхронизации, потому что мне нужно только обновить переменную bestSoFar в конце выполнения одного потока. Поэтому каждый поток в значительной степени должен выполняться полностью параллельно, за исключением небольшого критического раздела в конце.
Я использовал это в сравнении с последовательной грубой силой, и все еще требуется больше времени. Я не вижу другого объяснения, кроме того, что мои потоки запускаются последовательно, либо потому, что они сопоставляются с одним и тем же ядром или с одним и тем же собственным потоком.
Есть ли у кого-нибудь проницательность?