- •The Government of the Russian Federation
- •Постановка задачи
- •Введение
- •1. Теоретическая часть (обзор средств и методов реализации многопоточности в Java).
- •1.1 Процессы
- •1.2 Потоки
- •1.3 Запуск потоков
- •1.4 Завершение процесса и демоны
- •1.5 Завершение потоков
- •2. Методы использующиеся при работе с потоками.
- •2.1. Метод Thread.Sleep()
- •2.2. Метод yield()
- •2.3. Метод join()
- •3. Приоритеты потоков
- •4. Проблемы при реализации параллельных программ
- •4.1 Взаимная блокировка (deadlock)
- •4.2. Голодание (starvation).
- •4.3. Активная блокировка (livelock) .
- •Заключение теоретической части.
- •Заключение
- •Список использованных источников и литературы
Заключение теоретической части.
В данном обзоре описывается, хотя бы очень кратко, большая часть основных вопросов связанных с поддержкой параллелизма в Java. Надеюсь, мне удалось передать наиболее важные аспекты этой проблемы в достаточном для понимания объеме.
Для реализации поставленной задачи я буду использовать описанные процессы и потоки, но мне нет необходимости использовать описанные в обзоре методы, так как задача стоит в оценке быстродействия вычислении функции при использовании разного количества потоков.
Алгоритм работы программы.
Согласно этому алгоритму напишем текст программы. Листинг программы приведем ниже.
Приложение 1.
import javax. swing.*; //подключение библиотеки вывода окна //на экран
public class Vine {
static int x=0,y=0,z=1; //инициализация общих аргументов //функции
//**********************************подсчет c использованием многопоточности
public static class ThreadTest implements Runnable {
long before1=0;long after1=0; //переменные подсчета времени
public void run() {
double calc; //переменная подсчета значений функ //ции
before1 = System.currentTimeMillis(); //установка значений переменной вре //мени «до»
for (int i=0; i<5000; i++) {
//подсчет значений функции
calc =(Math.sin(i*y)*Math.cos(z*2))+(Math.cos(i*y)*Math.sin(2*z));
//условие вывода на экран промежу //точного значения
if (i%1000==0) { //условие вывода промеж. знач
after1=System.currentTimeMillis(); //установка значений переменной вре //мени «после»
//вывод на экран промежуточного //значения
System.out.format("%s count %d fixing %.4f time %d ms\n",getName(),(i/1000),calc,(after1-before1));
}
}
}
}
public static String getName() {
return Thread.currentThread().getName(); //возвращение имени потока
}
//*********************************подсчет без использования многопоточности
public static void free() {
long before2=0;long after2=0; //переменные подсчета времени
before2= System.currentTimeMillis(); //установка значений переменной вре //мени «до»
double calc; //переменная подсчета значений функ //ции
for ( int i=0; i<5000; i++) {
//подсчет значений функции
calc =(Math.sin(i*y)*Math.cos(z*2))+(Math.cos(i*y)*Math.sin(2*z));
if (i%1000==0) { //условие вывода промеж. знач
after2=System.currentTimeMillis(); //установка значений переменной вре //мени «после»
//вывод на экран промежуточного //значения
System.out.format("count %d fixing: %.4f time %d ms\n",(i/1000),calc,(after2-before2));
}
}
}
public static void main(String[] args) { //функция main()
//вывод запроса на экран
String input_x = JOptionPane.showInputDialog("Введите количество потоков:");
x = Integer.parseInt(input_x); //считывание значения в переменную
//вывод запроса на экран
String input_y = JOptionPane.showInputDialog ("Введите аргумент A:") ;
y = Integer.parseInt(input_y); //считывание значения в переменную
//вывод запроса на экран
String input_z = JOptionPane.showInputDialog ("Введите аргумент B:") ;
z = Integer.parseInt(input_z); //считывание значения в переменную
//вывод на консоль текста
System.out.format("<Выполнение программы без использования многопоточности>\n");
free(); //вызов процедуры подсчета значения //функции без многопоточности
//вывод на консоль текста
System.out.format("<Выполнение программы c использованием многопоточности>\n");
// Подготовка потоков
Thread t[] = new Thread[x];
for (int i=0; i<t.length; i++) {
t[i]=new Thread(new ThreadTest(),"Thread "+i);
}
// Запуск потоков
for (int i=0; i<t.length; i++) {
t[i].start();
System.out.format("%s <starter> \n",t[i].getName());
}
System. exit(0); //завершение работы программы
}
}
Проанализируем результат выполнения программы. Результат выполнения программы приведен ниже.
Приложение 2.
Результат 1.
При работе 5 потоков.
<Выполнение программы без использования многопоточности>
count 0 fixing: 0,9093 time 0 ms
count 1 fixing: 0,9974 time 16 ms
count 2 fixing: 0,5394 time 16 ms
count 3 fixing: -0,9384 time 16 ms
count 4 fixing: 0,5476 time 31 ms
<Выполнение программы c использованием многопоточности>
Thread 0 <starter>
Thread 1 <starter>
Thread 2 <starter>
Thread 2 count 0 fixing 0,9093 time 0 ms
Thread 2 count 1 fixing 0,9974 time 47 ms
Thread 2 count 2 fixing 0,5394 time 47 ms
Thread 2 count 3 fixing -0,9384 time 47 ms
Thread 1 count 0 fixing 0,9093 time 0 ms
Thread 1 count 1 fixing 0,9974 time 62 ms
Thread 1 count 2 fixing 0,5394 time 62 ms
Thread 1 count 3 fixing -0,9384 time 62 ms
Thread 1 count 4 fixing 0,5476 time 78 ms
Thread 3 <starter>
Thread 4 <starter>
Thread 0 count 0 fixing 0,9093 time 0 ms
Thread 0 count 1 fixing 0,9974 time 78 ms
Thread 0 count 2 fixing 0,5394 time 78 ms
Thread 0 count 3 fixing -0,9384 time 94 ms
Thread 0 count 4 fixing 0,5476 time 94 ms
Thread 2 count 4 fixing 0,5476 time 109 ms
Thread 3 count 0 fixing 0,9093 time 0 ms
Thread 3 count 1 fixing 0,9974 time 0 ms
Thread 3 count 2 fixing 0,5394 time 16 ms
Thread 3 count 3 fixing -0,9384 time 16 ms
Thread 3 count 4 fixing 0,5476 time 16 ms
Thread 4 count 0 fixing 0,9093 time 0 ms
Thread 4 count 1 fixing 0,9974 time 0 ms
Thread 4 count 2 fixing 0,5394 time 0 ms
Thread 4 count 3 fixing -0,9384 time 16 ms
Thread 4 count 4 fixing 0,5476 time 16 ms
Анализ: Согласно результату 1. видно что выполнении вычисления происходит за 31 мс, однако при использовании разбиения на 5 потоков мы видим что 0,1 и 2 поток слишком сильно запаздывают, а вот 3 и 4 поток выполняют вычисления за 16 мс. Такое запаздывание я связываю с загруженностью процессора другими процессами.
Для объективности проведем еще пару тестов с другим количеством потоков.
Результат 2.
При работе 3 потоков.
<Выполнение программы без использования многопоточности>
count 0 fixing: 0,9093 time 0 ms
count 1 fixing: 0,9974 time 15 ms
count 2 fixing: 0,5394 time 62 ms
count 3 fixing: -0,9384 time 62 ms
count 4 fixing: 0,5476 time 62 ms
<Выполнение программы c использованием многопоточности>
Thread 0 <starter>
Thread 1 <starter>
Thread 0 count 0 fixing 0,9093 time 0 ms
Thread 0 count 1 fixing 0,9974 time 0 ms
Thread 0 count 2 fixing 0,5394 time 16 ms
Thread 0 count 3 fixing -0,9384 time 16 ms
Thread 0 count 4 fixing 0,5476 time 16 ms
Thread 1 count 0 fixing 0,9093 time 0 ms
Thread 1 count 1 fixing 0,9974 time 0 ms
Thread 1 count 2 fixing 0,5394 time 0 ms
Thread 1 count 3 fixing -0,9384 time 0 ms
Thread 1 count 4 fixing 0,5476 time 16 ms
Thread 2 <starter>
Thread 2 count 0 fixing 0,9093 time 0 ms
Thread 2 count 1 fixing 0,9974 time 15 ms
Thread 2 count 2 fixing 0,5394 time 15 ms
Thread 2 count 3 fixing -0,9384 time 15 ms
Thread 2 count 4 fixing 0,5476 time 15 ms
Согласно результату 2. видно что выполнении вычисления происходит за 62 мс, если рассматривать этот результат в связке с предыдущим результатом, то видно что, одно и то же вычисление, происходит за разное время. Данный результат подтверждает то что на выполнение вычисления, влияют другие сторонние процессы, а так же использование не совершенного метода подсчета времени. Не зависимо от не совершенства метода из этого результата видно что при использовании разбиения на 3 потока значительное увеличение скорости вычисления, все потоки выполняют задачу за 16 мс.
Результат 3.
При работе 10 потоков.
<Выполнение программы без использования многопоточности>
count 0 fixing: 0,9093 time 0 ms
count 1 fixing: 0,9974 time 16 ms
count 2 fixing: 0,5394 time 16 ms
count 3 fixing: -0,9384 time 31 ms
count 4 fixing: 0,5476 time 31 ms
<Выполнение программы c использованием многопоточности>
Thread 0 <starter>
Thread 1 <starter>
Thread 0 count 0 fixing 0,9093 time 0 ms
Thread 0 count 1 fixing 0,9974 time 0 ms
Thread 0 count 2 fixing 0,5394 time 0 ms
Thread 0 count 3 fixing -0,9384 time 0 ms
Thread 0 count 4 fixing 0,5476 time 16 ms
Thread 1 count 0 fixing 0,9093 time 0 ms
Thread 1 count 1 fixing 0,9974 time 0 ms
Thread 1 count 2 fixing 0,5394 time 15 ms
Thread 1 count 3 fixing -0,9384 time 15 ms
Thread 1 count 4 fixing 0,5476 time 15 ms
Thread 2 <starter>
Thread 3 <starter>
Thread 4 <starter>
Thread 5 <starter>
Thread 6 <starter>
Thread 7 <starter>
Thread 2 count 0 fixing 0,9093 time 0 ms
Thread 2 count 1 fixing 0,9974 time 0 ms
Thread 2 count 2 fixing 0,5394 time 0 ms
Thread 2 count 3 fixing -0,9384 time 16 ms
Thread 2 count 4 fixing 0,5476 time 16 ms
Thread 3 count 0 fixing 0,9093 time 0 ms
Thread 3 count 1 fixing 0,9974 time 0 ms
Thread 3 count 2 fixing 0,5394 time 15 ms
Thread 3 count 3 fixing -0,9384 time 15 ms
Thread 3 count 4 fixing 0,5476 time 15 ms
Thread 4 count 0 fixing 0,9093 time 0 ms
Thread 4 count 1 fixing 0,9974 time 16 ms
Thread 4 count 2 fixing 0,5394 time 16 ms
Thread 4 count 3 fixing -0,9384 time 16 ms
Thread 8 <starter>
Thread 9 <starter>
Thread 7 count 0 fixing 0,9093 time 0 ms
Thread 7 count 1 fixing 0,9974 time 0 ms
Thread 7 count 2 fixing 0,5394 time 0 ms
Thread 7 count 3 fixing -0,9384 time 0 ms
Thread 7 count 4 fixing 0,5476 time 16 ms
Thread 6 count 0 fixing 0,9093 time 0 ms
Thread 6 count 1 fixing 0,9974 time 16 ms
Thread 6 count 2 fixing 0,5394 time 16 ms
Thread 6 count 3 fixing -0,9384 time 32 ms
Thread 6 count 4 fixing 0,5476 time 32 ms
Thread 4 count 4 fixing 0,5476 time 63 ms
Thread 8 count 0 fixing 0,9093 time 0 ms
Thread 8 count 1 fixing 0,9974 time 0 ms
Thread 8 count 2 fixing 0,5394 time 0 ms
Thread 8 count 3 fixing -0,9384 time 16 ms
Thread 8 count 4 fixing 0,5476 time 16 ms
Thread 5 count 0 fixing 0,9093 time 0 ms
Thread 5 count 1 fixing 0,9974 time 63 ms
Thread 5 count 2 fixing 0,5394 time 79 ms
Thread 5 count 3 fixing -0,9384 time 79 ms
Thread 5 count 4 fixing 0,5476 time 79 ms
Thread 9 count 0 fixing 0,9093 time 0 ms
Thread 9 count 1 fixing 0,9974 time 0 ms
Thread 9 count 2 fixing 0,5394 time 0 ms
Thread 9 count 3 fixing -0,9384 time 0 ms
Thread 9 count 4 fixing 0,5476 time 16 ms
Анализ: Согласно результату 3. видно, что выполнении вычисления происходит за 31 мс, однако при использовании разбиения на 10 потоков мы видим что 4,5 и 6 поток слишком сильно запаздывают, а вот остальные потоки выполняют вычисления за 16 мс что говорит об оптимальным временем выполнения вычисления.
Если посмотреть на результаты анализов тестирования то можно сделать следующие выводы:
Необходимо использовать другие методы подсчета времени выполнения задачи, которые бы исключали из подсчета времени время отводимое процессором на выполнение других процессов.
Необходимо использовать большее количество тестов для большей достоверности результата, с использованием других функций и большего количества аргументов.
Необходимо устранить следующие факторы для увеличения быстродействия, используя для этого приведенную таблицу.
Таблица 1.
Фактор |
Описание |
Как обнаружить/ определить проблему? |
Что было сделано для ее устранения? |
Издержки запуска библиотеки с поддержкой потоков |
Однократная издержка при запуске кода. Не имеет значения для большей части кода. Компонуется с запуском остальной части приложения |
За пределами типовых измерений внутри кода сравнить время выполнения последовательного приложения с многопоточным |
Не применимо Не подлежит настройке разработчиком |
Издержки запуска потоков |
Время создания потоков. Однократные затраты связанные с группировкой потоков. |
Измерить несколько проходов во всем многопоточном коде; |
Для компенсации этой издержки по возможности распределить по потокам циклы более высокого уровня или более длительные циклы |
Издержки на каждый поток (планирование цикла) |
Время, затраченное библиотекой с поддержкой многопоточности на распределение блоков задач по потокам |
Провести измерения только в коде, зависящем от быстродействия, или нетипичном планировщике задач; см. ниже |
Настроить планирование в своем коде; |
Издержки управления блокировкой |
Время, потраченное на управление блокировкой в важных разделах. Иногда используется при эталонном тестировании и сравнении разных реализаций. |
Понаблюдать за частыми вызовами блокировки с помощью такого инструмента, как VTune Performance Analyzer. В большинстве случаев в коде, отягощенном блокировкой, возникают гораздо более серьезные проблемы с блокировкой; |
Сократите блокировку для сокращения конфликтов блокировки и управления; |
В данной работе, исправления согласно пунктам по итогам анализа результатов, и факторов указанных в таблице 1 не производилось, так как эта задача в постановке задачи не ставилась.