Java и мультипроцессирование

Вопросы написания собственного программного кода (на любых языках)

Модератор: Olej

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Java и мультипроцессирование

Непрочитанное сообщение Olej » 20 фев 2015, 12:24

Вопрос тянется из вот этого IT-семинара (т.е. он возникал и раньше ... назывался лет 10 назад ;-) , но там специально ему был разговор посвящён).

Потоки в Java...
Когда объект Java наследует Thread или реализует интерфейс Runable - это поток ядра операционной системы, или внутренне реализуемый виртуальной машиной JVM (интерпретатором).

Ну а дальше: если это потоки ядра операционной системы, то при наличии N процессоров (ядер) ваши N потоковых объектов Java будут естественным образом масштабироваться на эти N процессоров, раскладываться 1:1.

Такая ситуация естественным образом наблюдается в компилирующих языках C, C++ и Go (да и то Go под вопросом для разных сред исполнения, операционных систем).

А в любом интерпретирующем языке (или исполняющем байт-код) вот такое естественное отображение потоков языка в потоки операционной системы может быть только если при создании потока Java создаётся новый экземпляр виртуальной машины (JVM), выполняющийся в новом потоке ядра.

А иначе, если потоки выполняются в едином интерпретаторе, то это моделирование потоков, и оно имеет право быть ... за одним исключением: такие потоки не могут быть разнесены между разными процессорами!
Это в точности та история, которая наблюдается в Python (хоть 2, хоть 3), где выполнение на 2-х процессорах 2-х потоков может быть ... вдвое длиннее чем на одном процессоре. :-o Это знаменитая проблема глобальной блокироки GIT в Python.

Ответ на этот вопрос стандарт языка Java не даёт.
И это естественно, потому что это зависит а). от конкретной JVM как в ней это реализовано и б). от платформы, для которой писалась JVM и её технических возможностей.

Следующий вопрос: как обстоит с этим дело в Linux? ... для самых актуальных для Linux JVM, как минимум: Sun/Oracle JDK + OpenJDK.
Где-то проскакивала информация, что (якобы) до JDK 1.2 были реализованы "зелёные" потоки, т.е. моделируемые в рамках единой виртуальной машины, а в нынешних реализациях - это нативные POSIX потоки.

Как это проверить (убедиться)?
Как будут масштабироваться потоки Java на N процессоров?

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Java и мультипроцессирование

Непрочитанное сообщение Olej » 20 фев 2015, 12:35

Olej писал(а):Как это проверить (убедиться)?
Как будут масштабироваться потоки Java на N процессоров?
Самый убедительный, по моему, способ для этого в любом языке программирования состоит в том, чтобы:
- запустить N потоков на N процессорах...
- с тем, чтобы потоки были абсолютно не взаимодействующие, без нужды синхронизаций, даже volatile данных...
- пусть каждый из них просто инкрементирует собственную переменную...
- и дать им поработать, скажем, 1 секунду.
- и сравниваем суммарно что наинкрементировали все N потоков.

И проделываем это при разных N.

P.S. вопрос (иногда спрашивают): а как менять N? на разном оборудовании прогонять с разным числом процессоров?
Это трудоёмко и громоздко ... но совсем необязательно ;-) .
Для той же Java это может быть что-то типа (на 4-х ядерном процессоре):
- 2 процессора:

Код: Выделить всё

$ taskset -c 0,2 java xxx  
- 1 процессор:

Код: Выделить всё

$ taskset -c 3 java xxx  
Сама JVM получает аффинити-маску, позволяющую ей задействовать только указанные процессоры.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Java и мультипроцессирование

Непрочитанное сообщение Olej » 20 фев 2015, 17:19

Olej писал(а): Самый убедительный, по моему, способ для этого в любом языке программирования состоит в том, чтобы:
- запустить N потоков на N процессорах...
- с тем, чтобы потоки были абсолютно не взаимодействующие, без нужды синхронизаций, даже volatile данных...
- пусть каждый из них просто инкрементирует собственную переменную...
- и дать им поработать, скажем, 1 секунду.
- и сравниваем суммарно что наинкрементировали все N потоков.

И проделываем это при разных N.
Я уже проделывал это как-то, и даже показывал здесь на форуме по ходу дела, и даже с кем-то обсуждали: параллельность + синхронизации (примеры) ... а потом что-то отвлекло от его завершения и забылось (ну да, это конец февраля 2014 года, когда снова проснулась компания Global Logic, и начались для них лекции, лекции, лекции...).

Но там уже есть всё (или почти всё) готовое, чтобы посмотреть и этот вопрос.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Java и мультипроцессирование

Непрочитанное сообщение Olej » 20 фев 2015, 22:07

Есть ещё один непонятный мне момент относительно потоков Java для этих экспериментов...
Запускаю приложение Java без всяких потоков (оно было показано в сравнении языков программирования):

Код: Выделить всё

[Olej@modules triangle]$ java triangle
координаты вершин в формате: X Y
вершина № 1 : завершение работы
И приложение завершается по EOF (^D)...

И уже после завершения приложения находим:

Код: Выделить всё

[Olej@modules SpeedThread]$ ps -A -L  | grep java | head -n3
25917 25917 ?        00:00:00 java
25917 25918 ?        00:00:00 java
25917 25919 ?        00:00:00 java
[Olej@modules SpeedThread]$ ps -A -L  | grep java | wc -l
158
[Olej@modules ~]$ top -p 25917
top - 21:02:37 up 11:11, 11 users,  load average: 0,55, 0,46, 0,35
Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie
%Cpu(s):  5,3 us,  1,6 sy,  1,3 ni, 91,7 id,  0,1 wa,  0,0 hi,  0,0 si,  0,0 st
KiB Mem:   8053260 total,  5366112 used,  2687148 free,   165856 buffers
KiB Swap:        0 total,        0 used,        0 free,  1932432 cached

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                          
25917 Olej      30  10 4245204 382012  17368 S  13,3  4,7   1:10.87 java                                                             
158 "остаточных" потоков ядра, запушенных от java, которые жрут весьма много памяти...

Это Java:

Код: Выделить всё

[Olej@modules triangle]$ java -version
java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)
Как это понимать?

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Java и мультипроцессирование

Непрочитанное сообщение Olej » 20 фев 2015, 22:26

Olej писал(а): Это Java:

Код: Выделить всё

[Olej@modules triangle]$ java -version
java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)
Как это понимать?
Использую другую JVM (за счёт переменных в .bashrc и перезапустить терминал - этого достаточно):
[Olej@modules ~]$ java -version
java version "1.7.0_75"
OpenJDK Runtime Environment (fedora-2.5.4.2.fc20-x86_64 u75-b13)
OpenJDK 64-Bit Server VM (build 24.75-b04, mixed mode)
То же беспоточное приложение:

Код: Выделить всё

[Olej@modules triangle]$ java triangle
координаты вершин в формате: X Y
вершина № 1 : завершение работы
И в итоге:

Код: Выделить всё

[Olej@modules SpeedThread]$ ps -A -L  | grep java | wc -l
233
[Olej@modules SpeedThread]$ ps -A -L  | grep java | head -n3
28235 28235 ?        00:00:00 java
28235 28236 ?        00:00:01 java
28235 28237 ?        00:00:00 java
Теперь их (потоков) после завершения приложения - 233.

Это у них родовое? :-o :lol:

Код: Выделить всё

[Olej@modules triangle]$ java triangle
координаты вершин в формате: X Y
вершина № 1 : завершение работы

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Java и мультипроцессирование

Непрочитанное сообщение Olej » 21 фев 2015, 19:57

Olej писал(а): Я уже проделывал это как-то, и даже показывал здесь на форуме по ходу дела, и даже с кем-то обсуждали: параллельность + синхронизации (примеры) ... а потом что-то отвлекло от его завершения и забылось (ну да, это конец февраля 2014 года, когда снова проснулась компания Global Logic, и начались для них лекции, лекции, лекции...).
Внимательное рассмотрение уточнённых результатов склоняет к выводу, что в JVM (что в OpenJDK, что в Sun/Orecle JDK), похоже, при создании потока (объекта наследуемого от Thread) создаётся новый исполняющий поток самой JVM, который и интерпретирует байт код Java-потока приложения.
(цифры можно посмотреть там по ссылке)

Ответить

Вернуться в «Программирование»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 4 гостя