4 процессора, 2 одновременных потока, почему увеличивается время обслуживания

Я хочу прояснить свою концепцию планирования потоков. Я уже задавал этот вопрос, но из-за отсутствия ответа я Я пытаюсь задать его удобным способом. Моя система имеет 4 процессора, когда я запускаю одну задачу, связанную с процессором, в потоке, который выполняется примерно за 30 мс. Когда я запускаю 2 задачи с привязкой к процессору в двух потоках, они завершаются примерно за 70 мс.

Почему 2 задачи, выполняемые в двух потоках, занимают в два раза больше времени?

Задача, связанная с процессором:

public class CpuBoundJob3  implements Runnable {
    //long t1,t2;
    public void run() {

            long t1=System.nanoTime();
            String s = "";
            String name="faisalbahadur";
            for(int i=0;i<10000;i++)//6000 for 15ms 10000 for 35ms 12000 for 50ms
            {
                int n=(int)Math.random()*13;
                s+=name.valueOf(n);
                //s+="*";
            }
          long t2=System.nanoTime();

        System.out.println("Service Time(ms)="+((double)(t2-t1)/1000000));
    }


}

Поток для запуска задачи:

public class TaskRunner extends Thread {
    CpuBoundJob3 job=new CpuBoundJob3();
    public void run(){

    job.run();  
    }
}

Основной класс:

public class Test2 {
int numberOfThreads=100;//for JIT Warmup
public Test2(){
    for(int i=1;i<=numberOfThreads;i++){for JIT Warmup
        TaskRunner t=new TaskRunner();
        t.start();
        }
    try{
    Thread.sleep(5000);// wait a little bit
    }catch(Exception e){}
    System.out.println("Warmed up completed! now start benchmarking");
    System.out.println("First run single thread at a time");

        //run only one thread at a time
            TaskRunner t1=new TaskRunner();
            t1.start();


    try{//wait for the thread to complete
        Thread.sleep(500);
        }catch(Exception e){}

    //Now run 2 threads simultanously at a time

    System.out.println("Now run 2 thread at a time");


        for(int i=1;i<=2;i++){//run 2 thread at a time
            TaskRunner t2=new TaskRunner();
            t2.start();


            }


}
public static void main(String[] args) {
    new Test2();    
    }
}

person Faisal Bahadur    schedule 12.01.2016    source источник
comment
Ваши потоки, вероятно, конкурируют за системные ресурсы   -  person redFIVE    schedule 12.01.2016
comment
Постарайтесь исключить накладные расходы, связанные с созданием потоков.   -  person Fred Porciúncula    schedule 12.01.2016
comment
Нет! То же самое и с пулом потоков.   -  person Faisal Bahadur    schedule 12.01.2016
comment
Вы также используете пул потоков при тестировании случая с одним потоком?   -  person Fred Porciúncula    schedule 12.01.2016
comment
Я проверил это. 1 поток в пуле 1 задача: время обслуживания около 35 мс. 2 потока в пуле 2 задачи: время обслуживания около 70.   -  person Faisal Bahadur    schedule 12.01.2016
comment
Не создавайте новые, худшие версии ваших предыдущих вопросов.   -  person Kayaman    schedule 12.01.2016
comment
Так что накладные расходы, вероятно, не ваша проблема. Вы должны попробовать выполнить задачи несколько раз, чтобы лучше понять. Попробуйте запустить 1000 задач с одним потоком, 2000 задач с одним потоком и 2000 задач с двумя потоками и посмотрите, что произойдет.   -  person Fred Porciúncula    schedule 12.01.2016
comment
Каяман, я пытаюсь каким-то образом получить ответ. Пожалуйста, помогите, если можете.   -  person Faisal Bahadur    schedule 12.01.2016
comment
Каяман, я вижу ответ на предыдущий вопрос прямо сейчас!   -  person Faisal Bahadur    schedule 12.01.2016
comment
На него ответили слишком поздно, но я понял.   -  person Faisal Bahadur    schedule 12.01.2016


Ответы (1)


Другое явление, которое иногда случается, — это «ложный обмен». Это происходит, когда один поток читает из той же строки кэша (обычно 64 последовательных байта, в зависимости от системы), которую записывает другой поток. Это плохо для кеша и замедляет доступ к памяти.

Когда я писал свою первую многопоточную программу, это произошло со мной следующим образом: я назначил один поток для работы с четными местами массива, а другой поток для работы с нечетными местами. Это совершенно потокобезопасно, но очень медленно, потому что, когда поток 1 записывает в массив в месте #n, поток 2 читает из места #(n+1), которое является той же строкой кэша, что и место #n, поэтому кеш продолжает становиться недействительным.

См. также https://en.wikipedia.org/wiki/False_sharing.

person Adi Levin    schedule 12.01.2016
comment
см. этот пост: stackoverflow.com/questions/34748495/ - person Faisal Bahadur; 13.01.2016