Я пишу многопоточное приложение в Java для улучшения производительности по последовательной версии. Это - параллельная версия решения для динамического программирования 0/1 задачи о ранце. У меня есть Intel Core 2 Duo и с Ubuntu и с Windows 7 Professional на различных разделах. Я работаю в Ubuntu.
Моя проблема состоит в том, что параллельная версия на самом деле занимает больше времени, чем последовательная версия. Я думаю, что это может быть то, потому что потоки все отображаются на том же потоке ядра или что они выделяются тому же ядру. Существует ли способ, которым я мог удостовериться, что каждый поток Java отображается на отдельное ядро?
Я прочитал другие сообщения об этой проблеме, но ничто, кажется, не помогает.
Вот конец основных () и все выполненные () для класса KnapsackThread (который расширяет Поток). Заметьте, что они, способ, которым я использую часть и дополнительный для вычисления 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 переменную в конце выполнения единственного потока. Поэтому каждый поток в значительной степени должен выполниться полностью параллельно за исключением того маленького критического раздела в конце.
Я выполнил это по сравнению с последовательной грубой силой, и тем не менее она занимает больше времени. Я не вижу никакое другое объяснение, чем это, мои потоки выполняются последовательно, или потому что они отображаются на том же ядре или на том же собственном потоке.
У кого-либо есть понимание?
Сомневаюсь, что это будет связано с использованием одного и того же ядра для всех потоков. Планирование зависит от операционной системы, но вы должны иметь возможность увидеть, что происходит, если вы поднимете менеджер производительности операционной системы - это, как правило, покажет, насколько занято каждое ядро.
Возможные причины, по которым это занимает больше времени:
Я предлагаю вам посмотреть, сколько времени требуется каждому из ваших рабочих потоков, прежде чем они завершатся. Возможно, у одного из потоков гораздо более сложная задача. Если это так, то накладные расходы, вызванные синхронизацией и т. Д., Легко съедят то, что вы получили от многопоточности.