Современные средства по управлению потоками (Executors, Fork/Join Framework) — КиберПедия 

Автоматическое растормаживание колес: Тормозные устройства колес предназначены для уменьше­ния длины пробега и улучшения маневрирования ВС при...

Индивидуальные и групповые автопоилки: для животных. Схемы и конструкции...

Современные средства по управлению потоками (Executors, Fork/Join Framework)

2022-10-10 56
Современные средства по управлению потоками (Executors, Fork/Join Framework) 0.00 из 5.00 0 оценок
Заказать работу

Ну и последнее, что мы с вами сегодня посмотрим – это Fork/Join.

This framework is designed to solve problems that can be broken into smaller tasks using the divide and conquer technique. Inside a task, you check the size of the problem you want to resolve and, if it's bigger than an established size, you divide it in smaller tasks that are executed using the framework. If the size of the problem is smaller than the established size, you solve the problem directly in the task and then, optionally, it returns a result. docs.oracle.com/javase/tutorial/essential/concurrency/

 

Представьте себе задачу, которая распадается на две, потом каждая распадается на две и т.д. Ну вспомните быструю сортировку. Так она и работает. И таких алгоритмов, когда это может быть (распад на две части) – полно! Вы скажете «И?». А представьте, что каждую задачу и подзадачу, мы хотим, чтобы это в отдельном потоке происходило. Но вдруг нам повезет при наличии многих ядер. Возможно где-то что-то будет параллельно исполняться. Я не хочу эти потоки сам создавать. Для этого есть пул! 21 век на дворе! Т.е. получается Fork/JoinFramework – это решение задачи, которая делится на подзадачи, но каждая подзадача здесь автоматически в отдельном потоке запускается. Т.е. вы просто делаете, кидаете туда в эту систему свой taskи говорите «вот это сделай мне!». Правда логику, как он делится на подзадачи прописываете вы, но запуск потоков и т.д. берет на себя этот Framework. И назвали это все Fork/Join Framework.

http://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html

Для того чтобы в этом Fork/Joinучаствовать вы должны дать эту задачу, которая делится. Вы должны знать логику своих вычислений и как задача распадается на две. Это вы должны решить. Но там есть нюанс. Дело в том, что могут быть задачи, которые возвращают результат, тогда вы должны наследовать от класса RecursiveTask. А бывает, что ваша задача просто допустим, что-то рисует и возвращает voidи тогда вы наследуете RecursiveAction. Это как бы два основных класса и вы выбираете от какого наследовать по вышеописанному критерию.

Далее обратите внимание, как это все красиво запускается. Смотрите… Создается объект Fork/JoinPool, вы берете этот созданные объект, вызываете у него метод и туда кидаете свою задачу. А класс вы наследовали либо от одного, либо от другого. Я создал объект этого класса и вот этот вот кидаю и говорю «на тебе! это будет вершина дерева!». И дальше пошло, пошло, пошло, пошло. И на выходе вы получите свой результат.

Единственно, что в этой книжке где-то они дали на столько плохой пример, что-то было настолько смешное и медленно работающее, что я все это выбросил и взял другой классический пример, который здесь применяется. Берется большой массив и находится его сумма. Можно, конечно, просто тупо сложить в одном потоке, а можно сказать «давайте мы будем складывать, дай мне весь диапазон». Я даю ему весь массив. А он говорит: «Ой! Так много! Я не буду!». Я могу только 100 чисел сложить. Он отнимает сотню, а все остальное подзадачи. И она делится-делится-делится. Понимаете, да? Меньше 100 мы вычисляем, больше 100 на подзадачу. Логика разбиения ваша, но сама механика – вы только должны наследовать класс и реализовать 1 метод. Смотрим…

Открываем проект: Java2-02\Threads\JavaApplication1

Смотрим на проект снизу, а именно с main. Создается массив из 10000 элементов, вызывается какой-то метод, который заполняет его случайными числами. Затем в лоб происходит суммирование для контроля, нам же сразу не надо. А то мало ли, что там ForkJoinнасчитает. А затем уже вызывается ForkJoinPoolи в него мы кладем объект класса sum, в котором мы говорим, что надо складывать массив a1 от 0 до length. Это конструктор с параметрами. Вот наш класс, который в этом Fork/Joinучаствует Sum. А invokeв данном случае, он вам возвращает результат. Это тоже сумма, потому что там мы же сумму вычисляем. И все задачи будут подзадачи возвращать, полученные в свою маленькую сумму, которая потом сложится и получится результат. По скорости их сравнивать не нужно. Это не та ситуация. Главное, что результат одинаковый.

run: 288258966861 288258966861 СБОРКА УСПЕШНО ЗАВЕРШЕНА (общее время: 0 секунд)

Вопрос: А какая скорость?

Ответ: Вопрос скорости в Javaочень скользкий. Помните я рассказывал, что виртуальная машина JIT-компиляция на лету определяет какой код требует JIT-компиляция и делает его максимально эффективным, и только после этого кэширует. Поэтому виртуальная машина в начале собирает статистику о том, кого нужно кэшировать. Если вы просто запустите программу голую и просто запустите другую программу голую, то не факт, что они были бы эффективны в варианте уже закешированном. Поэтому с чем вы сравниваете, кого с кем сравниваете – совершенно не понятно. И если брать книжку по производительности и почитать ее внимательно, то там автор прежде чем попытаться оценить производительность пишет «разогревающий код», который приведет к созданию кэша, и только потом пишется эксперимент, который… Ну и так далее.

Но! Если у вас есть свободные ядра, то часть расчетов может произойти параллельно. Само по себе это неплохо. Но с другой стороны, посмотрите на класс Sum – он написан для какого типа? Generic. Да! А это уже проблема. Правильно? Обертка и сборка мусора. Поэтому пока в Javaне избавятся от этой двойственной природы – системы типов, когда у вас есть ссылочные и простые, которые не могут быть в Generic, проблема все равно всегда будет. Они мечтают от этого избавиться.

RecursiveTask – потому что должна возвращаться сумма от каждой подзадачи. Но то что здесь в каждом объекте должны быть границы, конструктор с границами. Что нужно переопределять из этого Recursive (неважно какой именно)?compute(). А у того варианта void, который у нас был бы RecursiveAction.Вот как раз здесь идет от 100. Мы говорим: «Ой! 100 – это нормально. А если больше 100, то это надо на подзадачу». Т.е. если получается диапазон меньше 100, я считаю и что-то возвращается. А else – «Ой! Надо делать две задачи!» и elseраспадается на 2 задачи. Вот сумма левая, сумма правая. Диапазоны здесь заданы. Задача распалась на 2 составляющие. А дальше, откуда взялся fork/join? Почему такое название? Дело в том, что для одной задачи вы вызываете fork/join, а для другой вызываете compute(). compute() –это непосредственный вызов в том же потоке метода подзадачи, а fork–их запустят в отдельном потоке. Т.е. получается такая картинка.

Вот у меня Taskисходный. Но у меня же есть поток, который ее отрабатывает? Есть. Начала работать Task. Сработал else. Она распадается на две части. Одна задача. Вторая задача. Вот этот поток, вот туда куда я вызвал compute() – вот этот поток пойдет вправо. И здесь произойдет разбиение. Тоже на две. И этот поток тоже пойдет вправо.

А налево идет fork. Это что значит? Это значит, что здесь когда по левой, то будет создаваться новый поток. Вот в этой точке, поток, который у вас сюда пришел, он пойдет вправо, а по левой будет создаваться новый поток.

Я считаю, что здесь основным моментом является удобство. Не забывайте, всю вашу производительность и ваши чудеса, связанные с этим элементарно порушат обертки. Извиняйте.


Поделиться с друзьями:

Опора деревянной одностоечной и способы укрепление угловых опор: Опоры ВЛ - конструкции, предназначен­ные для поддерживания проводов на необходимой высоте над землей, водой...

Автоматическое растормаживание колес: Тормозные устройства колес предназначены для уменьше­ния длины пробега и улучшения маневрирования ВС при...

Индивидуальные очистные сооружения: К классу индивидуальных очистных сооружений относят сооружения, пропускная способность которых...

Таксономические единицы (категории) растений: Каждая система классификации состоит из определённых соподчиненных друг другу...



© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!

0.01 с.