Параллельное программирование в Java | Статья в журнале «Молодой ученый»

Отправьте статью сегодня! Журнал выйдет 29 января, печатный экземпляр отправим 2 февраля.

Опубликовать статью в журнале

Автор:

Рубрика: Информационные технологии

Опубликовано в Молодой учёный №22 (364) май 2021 г.

Дата публикации: 31.05.2021

Статья просмотрена: 12 раз

Библиографическое описание:

Ходжиматов, Ж. М. Параллельное программирование в Java / Ж. М. Ходжиматов. — Текст : непосредственный // Молодой ученый. — 2021. — № 22 (364). — С. 30-34. — URL: https://moluch.ru/archive/364/81691/ (дата обращения: 18.01.2022).



С появлением в последние годы многоядерных процессоров параллельное программирование — это способ в полной мере использовать преимущества новых рабочих лошадок обработки. Под параллельным программированием понимается одновременное выполнение процессов из-за наличия нескольких ядер обработки. Это, по сути, приводит к огромному увеличению производительности и эффективности программ в отличие от линейного одноядерного выполнения или даже многопоточности. Фактически он включает в себя разделение проблемы на подзадачи, одновременное решение этих проблем и затем объединение результатов решений подзадач. Java SE предоставляет структуру fork / join, которая позволяет вам более легко реализовать параллельное программирование в ваших приложениях. Однако в этой структуре вы хотите указать, как проблемы подразделяются (разделяются). С помощью агрегированных операций среда выполнения Java выполняет это разделение и смешивание решений за вас.

Ключевые слова: параллельное программирование, математические пакеты, MPI, WSTP.

Что такое параллельное программирование?

В отличие от многопоточности, где каждая задача является дискретной логической единицей более крупной задачи, задачи параллельного программирования независимы, и порядок их выполнения не имеет значения. Задачи определяются в зависимости от выполняемой ими функции или данных, используемых при обработке; это называется функциональным параллелизмом или параллелизмом данных соответственно. При функциональном параллелизме каждый процессор работает над своей частью задачи, тогда как при параллелизме данных процессор работает над своей частью данных. Параллельное программирование подходит для более крупной базы проблем, которая не вписывается в единую архитектуру ЦП, или проблема может быть настолько большой, что ее невозможно решить в разумные сроки. В результате, когда задачи распределяются между процессорами, он может получить результат относительно быстро.

Платформа Fork / Join в Java

Платформа Fork / Join Framework определена в пакете java.util.concurrent. Он состоит из нескольких классов и интерфейсов, поддерживающих параллельное программирование. Заметное различие между многопоточностью и параллельным программированием с этой структурой заключается в следующем: здесь обрабатывающая часть оптимизирована для использования нескольких процессоров, в отличие от многопоточности, где время простоя одного процессора оптимизируется на основе общего времени. Использование многопоточности в среде параллельного выполнения является дополнительным преимуществом этой платформы. Это реализация интерфейса ExecutorService, который помогает использовать преимущества нескольких процессоров.

Синтаксис:

RecursiveAction: не возвращает никакого результата; вы можете использовать его, например для инициализации большого массива некоторыми настраиваемыми значениями. Каждая подзадача работает отдельно с отдельным участком этого массива. Чтобы создать RecursiveAction, вам нужно создать свой собственный класс, который расширяется от java.util.Concurrent.RecursuveAction (который на самом деле является абстрактным классом) и реализовать его абстрактный метод compute ().

Чтобы вызвать RecursiveAction, вам необходимо создать новый экземпляр вашей реализации RecursiveAction и вызвать его с помощью ForkJoinPool.

RecursiveTask : подходит, когда вам нужно вернуть результат вашей задачи, например сортировка действительно огромного массива. Результат каждой подзадачи нужно сравнивать друг с другом. Эту задачу немного сложнее написать.

ForkJoinTask : это абстрактный класс, определяющий задачу. Обычно задача создается с помощью метода fork (), определенного в этом классе. Он похож на обычный поток, созданный с помощью класса Thread, но легче его.

ForkJoinPool : он предоставляет общий пул для управления выполнением задач ForkJoinTask. По сути, он предоставляет точку входа для отправки от клиентов, не относящихся к ForkJoinTask, а также для операций управления и мониторинга.

Методы

Compute (): когда вы вызываете compute () в правой задаче, на самом деле вы выполняете рекурсивный вызов.

Fork (): вызов метода fork () помещает недавно созданный PrimeRecursiveAction в очередь задач текущего потока.

Join (): когда вы вызываете join () для левой (ранее разветвленной) задачи, это должен быть один из последних шагов после вызова fork () и compute (). Вызов join () означает, что «я не могу продолжить, пока эта (левая) задача не будет выполнена». Но вызов join () — это не только ожидание. Задача, которую вы вызываете join (), все еще может быть в очереди (не украдена). В этом случае поток, вызывающий join (), выполнит объединенную задачу.

Стратегия Fork / Join Framework: стратегия разделяй и властвуй

Эта структура использует стратегию «разделяй и властвуй» для реализации параллельной обработки. По сути, он делит задачу на более мелкие подзадачи; затем каждая подзадача делится на подзадачи. Этот процесс применяется рекурсивно к каждой задаче, пока она не станет достаточно маленькой для последовательной обработки. Предположим, мы должны увеличить значения массива из N чисел. Это задача. Теперь мы можем разделить массив на два, создав две подзадачи. Разделите каждую из них еще раз на две подзадачи и так далее. Таким образом, мы можем рекурсивно применять стратегию «разделяй и властвуй», пока задачи не будут выделены в единичную задачу. Затем эта единичная проблема выполняется параллельно доступными многоядерными процессорами. В непараллельной среде мы должны циклически перебирать весь массив и последовательно выполнять обработку. Очевидно, что это неэффективный подход с точки зрения параллельной обработки.

Пример программы для реализации параллелизма в Java с помощью Fork / Join Framework

Выход:

Сложность параллельного программирования на Java

Одна из трудностей при реализации параллелизма в приложениях заключается в том, что коллекции не являются потокобезопасными, а это означает, что несколько потоков не могут управлять набором, не вызывая интерференции потоков или ошибок согласованности памяти. Collections Framework предоставляет оболочки синхронизации, которые в основном добавляют автоматическую синхронизацию к произвольной коллекции, делая ее потокобезопасной. Однако синхронизация вызывает конкуренцию потоков. Вам нужно избегать конкуренции потоков, потому что это предотвращает параллельную работу потоков. Агрегированные операции и параллельные потоки помогают реализовать параллелизм с небезопасными для потоков коллекциями.

Выполнение параллельного потока

Мы можем выполнять потоки последовательно или параллельно. Когда поток выполняется параллельно, среда выполнения Java разделяет поток на несколько подпотоков. Операции агрегирования повторяются и обрабатывают эти подпотоки параллельно, а затем объединяют результаты.

Когда вы создаете поток, это всегда последовательный поток, если не указано иное. Чтобы создать параллельный поток, вызовите операцию Collection.parallelStream. В качестве альтернативы вызовите операцию BaseStream.parallel.

Например, следующий оператор вычисляет средний возраст всех участников мужского пола параллельно:

двойное среднее = состав

.parallelStream ()

.filter (p -> p.getGender () == Person.Sex.MALE)

.mapToInt (Person :: getAge)

.в среднем()

.getAsDouble ();

Параллелизм не выполняется автоматически быстрее, чем последовательное выполнение операций, хотя может быть, если у вас достаточно данных и ядер процессора. Хотя агрегированные операции упрощают реализацию параллелизма, вы по-прежнему обязаны выяснить, подходит ли ваше приложение для параллелизма.

Литература:

  1. Воеводин В. В., Воеводин Вл.В. Параллельные вычисления. СПб: BHV-Петербург, 2002. 608 с.
  2. Эндрюс Г. Р. Основы многопоточного, параллельного и распределенного программирования; [пер. с англ.]. М.: Вильямс, 2003. 512 с.
  3. MathWorks. URL: http://www.mathworks.com (дата обращения: 01.01.2016).
  4. Maplesoft. URL: http://www.maplesoft.com (дата обращения: 01.01.2016).
  5. Wolfram. URL: http://www.wolfram.com (дата обращения: 01.01.2016).
  6. PTC Mathcad. URL: http://www.ptc.com/mathcad (дата обращения: 01.01.2016).
  7. Mäder R. Parallel Computing with Mathematica. Proc. 4th Intern. Workshop on Computer Algebra in Scientific Computing, Konstanz, Sept. 22–26, 2001, p. 399.
  8. Schreiner W., Mittermaier C., Bosa K. Distributed Maple: parallel computer algebra in networked environ-ments. Journ. of Symbolic Computation, 2003. vol. 35, iss. 3, pp. 305–347.
  9. Kucan J. Multi-threading, multi-core and parallel calculation in Mathcad. URL: http://blogs.ptc.com/2012/05/16/multithreading-multi-core-and-parallel-calculation-in-mathcad/ (дата обращения: 01.01.2016).
  10. Intel® Math Kernel Library (Intel® MKL). URL: https:// software.intel.com/en-us/intel-mkl (дата обращения: 01.01.2016).
Основные термины (генерируются автоматически): параллельное программирование, задача, подзадача, процессор, реализация параллелизма, абстрактный класс, параллельная обработка, параллельный поток, самое дело, функциональный параллелизм.


Задать вопрос