Паралельна обробка з багатоядерною Java? заявки

Оригінал статті ви можете знайти тут http://www.coopsoft.com/ar/CalamityArticle.html

Включено в нову Java? Випуск SE 7 — це так звана легка форма Fork-Join. Коли ви берете ретельний, всебічний погляд на те, що робить ця система і як це робиться, тоді ви побачите, що ця схема є неадекватним академічним експериментом, на підставі якого видається науковий документ, а не легкий механізм.

Ця стаття пояснює, чому (5500 слів) [так, це довго)

Автор: Едвард Харнед

Старший розробник, Cooperative Software Systems, Inc.

Січень 2011 р. [Оновлено липень 2016 р.]

Що таке Легка форма Fork-Join?

Основна структура Fork / Join (F / J) — це структура, яка підтримує паралельне програмування, де проблеми рекурсивно розбиваються на менші частини, вирішуються паралельно і рекомбінуються, як це описано в цьому псевдокоду з Java Fork / Join Framework:

Вирішити результат (Проблемна проблема) {

If (проблема невелика)

безпосередньо вирішити проблему

else {

розділити проблему на незалежні частини

вилка new підзадач для вирішення кожної частини

приєднати всі підзадачі

скласти результат від підрезультатів

}

}

Якщо б тільки справжнє рішення було таким просто. Для того, щоб зробити цю роботу, розробник баз даних повинен побудувати паралельний движок всередині Java? Віртуальна машина, копіюючи поточний вихідний код JDK, компілятори, точку доступу, різні періоди виконання та реалізацію — не вірогідний сценарій. Отже, єдиним практичним рішенням є створення сервера додатків.

Якщо тільки легкий F / J Framework був синьо-стрічковим сервером додатків. На жаль, ця система не є професійним сервером додатків. Це навіть не API. Основою є академічний експеримент для дослідження Java Fork / Join Framework. Це неадекватний, не легкий вага.

Частина друга цієї серії, додана в січні 2013 року, присвячена проблемам створення цієї системи як паралельного двигуна за замовчуванням для масових операцій в JDK1.8.

Ці статті стають надто тривалими для зручного читання, оскільки вони містять подробиці для підтримки кожної точки. Ось завантажувана консолідація у форматі PDF, яка використовує статтю як посилання. Набагато простіше переварити.

Частина третій цієї серії, додана в січні 2014 року, стосується нездатності підвищити ефективність паралельних операцій.

Система F / J просто не належить до JDK. Наступна частина цієї статті є критикою лише в тому випадку, коли вона стосується основи, яка є частиною стандартної Java-версії ?.

Критика

Є основні перешкоди для цієї структури, що є частиною JDK. Основою F / J є:

  1. несправний менеджер завдань
  2. неефективний
  3. спеціальне призначення
  4. повільний і невидатний
  5. надзвичайно складний
  6. не вистачає професійних атрибутів
  7. академічне заняття
  8. неадекватний за обсягом
  9. не API

Висновок.

Неправильний диспетчер завдань

Технологія Fork-Join розбиває твір на фрагменти та об’єднує результати. Підпорядкована практика, яка дозволяє проміжному приєднанню () для кожної fork () може працювати тільки в керованому середовищі.

Фатальний недолік з F / J Framework полягає в тому, що він намагається керувати проміжним з’єднанням () у завданні за межами контрольованого середовища. Тільки операційна система (O / S) або псевдо O / S можуть керувати проміжним приєднанням () у задачі. (Те, що вони називаються завданнями чи процесами, все одно.)

Коротко: коли завдання вимагає ресурсу або служби (пам’ять, файловий файл, join ()), він переходить до O / S, остаточного контрольованого середовища. Якщо запит поставить поточне завдання в стан очікування, O / S перемикає контекст завдання у призупинену чергу та перемикає новий контекст завдання з активної черги для виконання процесора.

Диспетчер завдань додатків (pseudo O / S), як Cilk або jCilk, може працювати лише тоді, коли програма проходить через неї (використовуючи компілятор та runtime, що створює контрольоване середовище) для запиту ресурсів або служб, таких як join (). Таким чином, менеджер може відключити / ввімкнути псевдопроцесори, які він контролює.

Базові основи програм просто не мають можливості дізнатися про середовище виконання програми, тому не існує способу на цій чудовій, зеленій землі, рамка додатків може зробити перемикач контексту для підтримки проміжного з’єднання ().

Відповідь JDK1.7 F / J Framework на проміжний приєднання () без контекстного перемикача — це «продовження потоків». Тобто, система створює додаткові тимчасові потоки, щоб продовжувати отримувати завдання додатків з deques та черги для подання під час підключення потоку входить в стан очікування Це може призвести до величезної кількості потоків для кожного запиту. (StackOverflow має один з понад 700 потоків продовження, необхідних для завершення одного виклику.) — Бездоганна помилка.

Відповідь JDK1.8 F / J Framework на проміжний приєднання () без контекстного перемикача — це «продовження отримання». Тобто система позначає об’єднання завдання, як логічно чекає, і потік продовжує отримувати та виконувати завдання з dque. Це може призвести до зависання (потоку в режимі очікування), коли рівень рекурсії стає довгим. Доказ у профіліреторі. (Ви можете завантажити вихідний код для демо-версії MultiRecurSubmit.java нижче.)

Крім того, виникає проблема помилок / винятків у згодом отриманих завдань.

  • Оскільки стек зберігає весь потік, може F / J Framework обробляти стек-переповнення проблем?
  • Чи може F / J Framework знайти записи стек для першого об’єднання завдання, або другий, або третій для виправлення помилок?
  • Чи може F / J Framework відновити і відновити інші пов’язані завдання в інших deques?

Відповідь не на все перераховане вище.

Давайте не забувати про асинхронне використання зовнішніх ресурсів завдань. Часто ресурс асоціює запит з потоком, який зробив запит:

Thread caller = thread.currentThread ();

Коли перші завдання виконує fork-join під час асинхронного дзвінка, той самий потік виконує завдання, що розгортається. Якщо це нове завдання не вдається,

  • Що відбувається з асинхронним запитом до зовнішнього ресурсу, оскільки вони обидва пов’язані з одним потоком?
  • Що відбувається з ручками, регістрами та пам’яттю, оскільки між завданнями немає чистої перерви (контекстного перемикача)?

Відповідь — це невизначеність до всього перерахованого вище.

Поточна обробка завдань JDK1.8 для F / J Framework — безпомилкова невдача. Незабаром, це лямбдафікація структури, яка повинна виявитися цікавою, але невдалою.

Проміжний приєднання () є не єдиним джерелом надмірного створення потоків за допомогою цієї системи.

Введено в JDK1.7 Phaser Class. Цитувати JavaDoc:

«Фазисери можуть бути багаторазовими (тобто побудовані в деревних структурах), щоб зменшити суперечність. Фазири з великою кількістю партій, які в іншому випадку можуть зазнати важкі витрати на суперечки щодо синхронізації, можуть бути встановлені таким чином, щоб групи субфазерів мали спільного батька «.

У JavaDoc не згадується, що при використанні великої кількості учасників система створює «компенсаційні потоки», щоб продовжувати отримувати завдання додатків з деки та черги для подання, тоді як кожна початкова гілка очікує на отримання субфакторів. Ці «компенсаційні потоки» можуть бути настільки надмірними, що вони роблять проблему «продовження потоків», наведеній вище, здаватися лайкою. Подивіться на себе. (Ви можете завантажити вихідний код демо TieredPhaser.java нижче.)

Представлений JDK1.8 є CompletableFuture класом. Цитувати JavaDoc:

«Майбутнє, яке може бути явним чином завершено (встановити його значення та статус), і може включати залежні функції та дії, які породжують його завершення».

У JavaDoc не згадується, що при використанні великої кількості залежних функцій з методом get (), система створює «компенсаційні потоки», щоб продовжувати отримувати завдання програми з деке та черги для подання. Знову ж таки, ці «компенсаційні потоки» можуть бути настільки надмірними, що вони роблять проблему «продовження потоків», наведеній вище, здаватися лайкою. Подивіться на себе. (Ви можете завантажити вихідний код для демонстрації MultiCompletables.java нижче.)

Проблемою є завдання, які потрібно зачекати. Коли завдання потрібно зачекати на будь-який ресурс, структура повинна від’єднати завдання від потоку. Ця структура не може відокремити завдання від нитки, тому вона знову і знову і знову намагається отримати інші засоби.

Повторне накладання F / J Framework нагадує, як грати битком. Там завжди настає час, коли ніяка кількість виправлень не буде працювати, оскільки вона ніколи не розглядає основний недолік —

Будь-яке очікування без контекстного перемикача є абсолютним, загальним, повним збійком.

Є альтернатива? Звичайно

Використання окремої структури для проведення проміжних результатів, а не за допомогою проміжного з’єднання () — це проста альтернатива, і вона має похвальні переваги:

  • Це не вимагає жахливої ​​складності управління завданнями.
  • Він може легко підтримувати циклічні залежності.
  • Він може легко обробляти синхронні та асинхронні обробки завершення.
  • Це передбачає
    • спосіб відслідковувати запит протягом усього життя, щоб допомогти у виявленні / виявленні помилок.
    • можливість часу та скасування запитів.
    • можливість збирання статистики для налаштування.

Помилка F / J Framework не має місця в JDK.

Неефективний

Припустимо java.util.concurrent.RecursiveTask, який підсумує довгий масив у методі compute ().
Sum left = нова Сума (масив, низький, середній);

Сума правильна = нова Сума (масив, середній, високий);

 

Sum left   = new Sum(array, low, mid);

Sum right = new Sum(array, mid, high);

 

left.fork();

long rightAns = right.compute();

long leftAns   = left.join();

 

return leftAns + rightAns;

На рівні 1 ми розбиваємо масив, створюючи два нові завдання для наступного рівня. Ми випускаємо вилку () для лівого боку та обчислюємо () для праві. Вилка () додає завдання до тієї ж робочої нитки. Обчислення () поміщає елемент у стек і продовжує виконання.

У другому класі compute () ми робимо те ж, що й вище.

Зрештою ми дістаємось донизу, де compute () фактично сумує масив, який повертає значення для останнього елемента в стеку. Той останній елемент може потім видати приєднання () для останньої fork (), яку він зробив. Те, що ми зробили, полягає у створенні завдань для подальшого завантаження по ланцюжку робочої сили і завдань, які можуть вкрасти інші робочі нитки.

Оскільки всі розгорнуті завдання виконуються в одній і тій же робочій послідовності, дебати робочих крадіжок будуть битися один з одним у верхній частині деке під час розгортання Завдань. Мало того, що це, на жаль, неефективне, це також передбачає суперечність між потоками крадіжки робітників. Спори — це саме те, на що повинно уникнути робота-крадіжка. Але насправді суперечка полягає в тому, що виробляє алгоритм викрадення робочої сили. Те, що ми маємо, — це одна черга з базою ниток, що борються над елементами. Чим більше масив, тим очевидніше це стає.

У підрозділі Java Fork / Join Framework, розділі 4.5 Завдання місцевості «[framework] оптимізований для випадку, коли робочі теми локально споживають переважну більшість завдань, які вони створюють. … Як видно на малюнку, в більшості програм відносна кількість викрадених завдань складає не більше декількох відсотків. «Навіть оригінальний науковий документ показує, що робота-крадіжка є неефективною.

Ця структура ніколи не може ефективно функціонувати у високопродуктивному середовищі. Гіпотетичний приклад:

Скажімо, існує 10 робочих потоків, forking генерує 100 завдань, і процес обробки фактичного обчислення займає 1 мілісекунду. Тому для обробки завдань послідовно буде потрібно 100 мілісекунд.

Використовуючи алгоритм балансування навантаження, який рівномірно розподіляє роботу серед всіх робочих потоків, час завершення роботи складає близько 10 мілісекунд.

Використовуючи крадіжку роботи, якщо одна робоча нитка робить 80% завдань та інших робочих потоків іншим, то час завершення роботи складає близько 80,3 мілісекунд.

Тоді виникає проблема голоду. Деякі робочі нитки стають насиченими роботою, залишаючи інші голодні робітники крадіжок.

Для студента роблять розрахунки на ноутбуці — так що. Для корпоративного сервера обробка транзакцій — ой.

Чи є кращий спосіб? Абсолютно

Це називається балансуванням навантаження методом збирання розсіювання.

У 2010 році автор дав розробнику F / J розробника концепцію розсіювання, що складалася з концептуального принципу, який мав розподілений вміст. Розробник програмного забезпечення F / J ігнорував його повністю. З тих пір автор прикрасив доказ поняття у повнофункціональний проект із відкритим кодом на SourceForge.net. Ви можете побачити для себе.

Ця заплутана, неефективна структура не має бізнесу в основній Java.

Спеціальне призначення

Брайан Гетц пише: «Прикріпіть собі вилку», ввівши класи класу ParallelArray та Fork / Join framework. Він визнав обмеження цих класів лише для «сукупних операцій даних». Як зауважив Брайан, система F / J виключно для стиснення номерів.

У системі F / J немає атрибутів професійного багатокористувацького сервера додатків (див. Вище). Тому його не слід використовувати для інших цілей, крім його первісної мети. Але на цьому земля розробники не зможуть дотримуватися необгрунтованих обмежень. (Деякі навіть не дотримуються розумних правил.)

Рекомендовані обмеження:

  • повинен бути простий (від 100 до 10000 базових обчислювальних кроків у методі обчислення);
  • Обчислити лише інтенсивний код
  • немає блокування
  • немає введення / виводу
  • немає синхронізації

Ви задаєтесь питанням, чому> 100, <10k обчислювальних кроків?

> 100 пов’язано з проблемою викрадення роботи. Всі завдання, що розгортаються, йдуть в ту саму дірку, яка робить інші пошукові теми для роботи. Коли нитки зустрічаються, вони повертаються назад і шукають десь інше. Оскільки там ніякої роботи ніде більше, вони намагаються повторювати таку саму декларацію, і знову, і знову, поки потік нарешті не завершить роботу сама по собі. Ви можете побачити доказ, завантаживши вихідний код класу LongSum.java нижче. Отже, працюйте повільно або не буде паралелізму.

<10k має відношення до проблеми join (). Оскільки система F / J не може виконати чисте керування завданнями (див. «Неправильний диспетчер завдань» вище), коли Завдання фактично чекають незалежно від потоку, коли вони називають join (), система повинна створити «thread продовження», щоб уникнути зупинки. Там може бути тільки обмежений час, перш ніж все розвалиться. Отже, бігати швидко або померти.

Що стосується інших обмежень — будь-яке фактичне блокування ниток, без знання основи, напевно, призведе до закриття всієї структури. Оскільки немає можливості переглядати внутрішні елементи, скасувати синхронні запити та абсолютно ніякого способу не враховувати будь-який запит, єдиною альтернативою для вирішення проблеми стійкості є вбивство JVM. Реальне партнерське рішення для бізнесу.

Неправильне використання рамки вже розпочато:

Пора Java: Коли використовувати ForkJoinPool vs ExecutorService — JavaWorld

Незабаром люди знайдуть застосування для цієї структури, про яку ніколи не уявляли. Це перший Закон розробки програмного забезпечення, який слідує Закону про непередбачені наслідки.
Рамка F / J не належить до основної Java.

Повільна і незчиненна

Швидкість

Швидкість є актуальною для інших продуктів Fork-Join. У цьому випадку швидкість в порівнянні з проектом TymeacDSE. Один виклик підсумовування передає продукт TymeacDSE в 3-4 рази швидше, ніж F / J Framework. (Ви можете завантажити вихідний код нижче.)

Оскільки продукти не можуть безпосередньо порівнювати — Framework F / J має обмежений обсяг, TymeacDSE — повнофункціональний сервер додатків — порівняння має включати в себе внутрішні структури.

F / J Framework використовує неефективну парадигму крадіжки підручників (вище), яка робить тематичні переходи шукати роботу і непотрібно розбиває роботу на непотрібні завдання.

Скажімо, є масив елементів 1M, а послідовний поріг становить 32K, тоді для паралельного підрахунку масиву потрібно 32 завдання. Проте, використовуючи приклад коду вище, спосіб генерує додаткові 31 завдання на шести рівнях лише для рекурсивного розбиття масиву на дві частини і join (). Це майже вдвічі більше робочого навантаження на нитки, які могли б інакше виконувати корисну роботу.

Нитки не можуть отримати нові запити, поки вони не завершать всю попередню роботу. (Тобто вони повинні вичерпати всі робочі місця, перш ніж вони зможуть перейти до черги подачі.) Оскільки немає окремої структури для проведення проміжних результатів, кожний розкол (fork ()) повинен зачекати (join ()) до наступного розщеплюється, вільно нагадує це:

  • fork()
  • join()

TymeacDSE використовує балансування навантаження, алгоритм збору розсіювання, який негайно подає роботу на потоки. Не існує окремої черги для подачі та не існує завдань розбиття / очікування. Таким чином, вищевказаний вище приклад 1M масив просто приймає 32 завдання для сукупності масиву паралельно. TymeacDSE використовує окрему структуру для всіх дзвінків як для відстеження роботи, так і для проведення проміжних результатів. Тому TymeacDSE дозволяє це:

  • fork () стільки разів, скільки необхідно для поширення роботи серед усіх процесорів, повертаючи проміжний результат на сервер для кожного обчисленого значення.
  • Завершивши роботу, виконайте всі проміжні результати. Яка може включати в себе розгалуження масив результатів.

Що це означає для програм, таких як сортування та карта / зменшення, це те, що TymeacDSE може використовувати повну колекцію процесорів для сортування або картування даних, а потім використовувати повний набір процесорів для об’єднання чи зменшення проміжних результатів. Використання всіх процесорів без очікування (join ()) робить TymeacDSE швидко.

Непотрібний

Як правило, масштабування передбачає, що коли ви додасте більше рівня процесора / потоку, ви зменшуєте час до завершення. Структура F / J Framework не дозволяє масштабувати.

  • Переплетення обробки клієнтських викликів / серверів
  • запасні нитки, необхідні для допомоги з проблемою очікування join () (див. вище),
  • а також код користування крадіжкою роботи
    • (потоки потрібно серійно шукати роботу серед усіх деків,
    • нитки споживають переважну більшість завдань, які вони створюють, так що додавання більшої кількості процесорів / потоків не впливає на паралелізм)

Працює лише на невеликій кількості процесорів. Ця конструкція ніколи не може бути масштабною для сотень або тисяч процесорів. Накладні витрати та голодування ниткодію знецінюють переваги додаткових процесорів.

TymeacDSE масштабує тисячі процесорів. Це просто питання дизайну. Коли архітектор відділяє клієнт-виклик, обробку користувача та керування сервером, то все це можливо. Створення індексу над структурою керування потоками / чергами легко, коли немає кодованих заплутань.

Швидкість і масштабованість — це лінчіни розпаралелювання. Повільна та непередавана служба додатків не належить до JDK.

Надзвичайно складний

«Зробити речі якомога простіше, але не простіше». Альберт Ейнштейн

«Ускладнений не є ознакою того, що ви розумні. Це ознака того, що ви програли. «Гілад Брача

«Є два способи побудови програмного забезпечення.

Один із способів полягає в тому, щоб зробити це таким простим, що, очевидно, немає недоліків.

І інший шлях — зробити це настільки складним, що немає очевидних недоліків «. К. А. Р. Хоаре

Класи F / J —

  • має багато, багато рівнів спадщини,
  • вкладені класи на вершині вкладених класів
  • змінні екземпляра, що використовуються безпосередньо іншими класами (відомі як «взаємозв’язок рівня представлення серед класів»),
  • код від захоплення хакерів без коментарів про те, що він робить
  • доморощені деки та черги замість стандартної Java? Заняття
  • і так багато іншого.

Методи програмування використовують бітові перемикачі (як-от код асемблера) та пряме маніпулювання пам’яттю (наприклад, C-код). Код виглядає більше як стара програма мови C, яка була сегментована в класи, ніж структура O-O.

Вбудована програма вбудовується в виклик-клієнт, який також містить код обслуговування користувача. Це вперед і назад, один, який називає інший, який називає першим, є класичним прикладом коду спагетті. Протягом більше сорока років програмісти, як відомо, відмовляються від заплутаних дзвінків, оскільки код стає нечітким.

Система настільки сильно залежить від класу [sun.misc.] Unsafe, що система F / J не є Java? програма Це псевдо-C програма. Очевидна необхідність писати на мові псевдо-C — отримати достатню кількість швидкості за допомогою попередньої оптимізації коду, оскільки робота-крадіжка настільки неефективна (нижче). Звичайно, це додає ще один рівень складності.

Чому це має значення?

  • Чим більший і складніший програмний продукт, тим більше, що може стати неефективним, тим сильніше він стає крихким, чим коротший час між несправностями.
  • Код є настільки жахливо складним, що досвідчені розробники скажуть вам, що це буде тільки з цієї причини.
  • Це робота компіляторів JIT для оптимізації коду. Незалежно від того, наскільки розумним і розумним є розробник, жодна людина не може передбачити середовище виконання. Передчасно оптимізований код зазвичай не може бути оптимізованим для JIT.
  • Гейзер небезпечних класів, використовуваних для виконання, чутливий до архітектури процесора, пам’яті та інших апаратних залежностей. Код може виконувати по-різному між випусками тієї ж самої архітектури, яка може вплинути на переносимість і навіть на безпеку.
  • Молодший Java? програмісти не можуть зрозуміти цей код, значно менше знайшовши робочі рамки, коли виникають проблеми — що таке обслуговування. Система F / J проблематична для розуміння будь-яким іншим, ніж оригінальними архітекторами. Сумнівно, що експериментальна група перехідних експериментів може зберегти цей надзвичайно складний код протягом його життя.

Цей надзвичайно складний код не належить до JDK.

Відсутність професійних атрибутів галузі

Програмісти програми рано навчаються на цьому:

  • Програми не працюють, як правило, в найгірший час, отже, виправлення помилок є найважливішим
  • Потоки знову ж таки зазвичай в найгірший час
  • Програмне забезпечення потребує настройки (балансування ресурсів)
  • Адміністратори іноді потребують сповіщення (також називають сповіщенням)
  • Журнали — королівська незручність, але необхідна
  • Інтерфейси в структурі для моніторингу продуктивності та функціональності управління є критичними
  • Програмне забезпечення має бути корисним для широкого кола комп’ютерних потреб
  • Спільний копія має бути доступною для ресурсів консерватора

У системі F / J немає жодного з них.

  • Немає виявлення помилок / відновлення / звітності (крім виключених виключень)
  • Немає виявлення стійла і, звичайно ж, відсутність витримки (потребує моніторингу)
  • Немає моніторингу середовища виконання, щоб висувати аномалії
  • Є лише мізерна збірка статистичних даних для аналізу продуктивності та настройки
  • Існує відсутність сповіщень або ведення журналу (для їх налагодження та звітування про помилки необхідний початковий рівень, потрібний певний спосіб дізнатися, що сталося).
  • Оскільки внутрішня структура настільки переплітається з викликаючим клієнтом, майже неможливо змінити керуючі змінні
  • Немає доступності для загального використання додатків. Це лише для обчислення інтенсивних завдань. При використанні інших, крім чистих, короткочасних обчислень, виникають серйозні проблеми з управління завданнями (див. Нижче)
  • Як написано в даний час, структура не може бути віддаленим об’єктом, оскільки існують заплутування коду абонента / сервісу.

Служба додатків без професійних атрибутів галузі не має місця в JDK.

Академічні вправи

Алгоритм викрадення робочої сили з використанням деки — це лише академічний інтерес. Є багато статей, присвячених роботі-крадіжці в Інтернеті, але жоден з них не призначений для загального програмування.

Припускаючи місцеположення довідки, розмістивши підзавдання назад у деке, з якого вони прийшли, і припускаючи, що одна і та ж потока буде обробляти підзадачу, це абсолютно бездоганно. Це може виглядати добре на папері, але на Java? компілятор, JIT-компілятор і смітник-збирач змінюють пам’ять. Крім того, Java? програми іноді працюють під двома віртуальними машинами (на мейнфреймах запускається Linux, під VM і Linux працює JVM), і немає гарантії відображення Java? нитки до потоків O / S (див. JRockit та інші.)

Викрадений робочий викрадений рахунок лише теоретичний інтерес. Для того, щоб користуватися галуззю, рахунок повинен включати в себете, чи виконується чи блокується потоком власника, тривалістю черги під час обробки і час, який потрібно для обробки завдання.

Внутрішній метод F / J коментує сайт численних наукових праць як основу їх існування. Незважаючи на те, що код відповідає найвищим академічним стандартам, ці облікові дані не є головним у створенні швидкої, масштабованої служби додатків для розробників. Більш того, «Огляд реалізації» у ForkJoinPool описує складність, яку незрозумілі лише простих смертних, що порушують час, що дотримується думки, що програма документація для програмістів, щоб допомогти їм знайти робочі рамки, коли помилки виникають.

«Будь-який дурень може написати код, який комп’ютер може зрозуміти. Хороші програмісти пишуть код, який людина може зрозуміти «. Мартін Фаулер

Чому це турбота?

  • Основна увага приділяється попереднім академічним дослідженням та дотриманню наукових принципів, а не корисності та зручності у широкій області.
  • Дизайн має відповідати підручнику, а не бути інноваційним.
    • Техніка викрадення робочої сили, в той час як наукова, є для дуже обмеженої практики (строгі, повністю суворі, терміно-суворі обчислення), і вимагає від компілятора / runtime підтримки (закрите середовище) працювати добре.
    • Немає альтернатив для крадіжки робочих місць, таких як збирання розсіювання, оскільки альтернативи не відповідають навчальному плану.
  • Справжня аудиторія — це академічна спільнота, а не спільне програмування, оскільки система F / J є модифікацією оригінального академічного експерименту.

Система F / J — це лише академічне підприємство, яке не належить до JDK.

Недостатньо у сферах

Використання класу небезопасних не дозволяє будь-коли знизити рівень F / J для роботи на JavaME.

Система F / J не може працювати у значній частині середовища JavaEE. Програми EJB та сервлету зазвичай використовують сервер RMI при використанні рамок для потоку. Проте, система F / J не може працювати з RMI, IIOP, POA або іншими мережевими технологіями.

Переплетення коду абонента / сервера перешкоджає запуску F / J як серверу.

Система F / J призначена тільки для роботи в тривіальному сегменті комп’ютерного світу:

  • тільки на JavaSE
  • Використовуючи жорсткі структури даних,
  • на високопродуктивних робочих станціях (16+ процесорів без гіперпотоків)
  • робити лише обчислювальні роботи
  • без завдання введення / виводу, відсутність взаємодії та відсутність взаємодії.

і лише для сукупних операцій з колекцій елементів, що мають регулярну структуру. Тобто, ви повинні вміти висловлювати речі з точки зору застосування, зменшення, фільтрування, картування, копіювання, сортування, унікальності, парних відліків тощо — тут немає програмного забезпечення загального призначення.

Система F / J призначена лише для роботи за одним запитом одночасно.

Гіпотетичний приклад:

Скажімо, існує декілька потоків робочих F / J і

Є багато користувацьких потоків, що подають запити:

  • Робочий потік підхоплює перший запит, і в остаточному підсумку інші робочі нитки підбирають вирішені завдання з першого запиту.
  • Інші подані запити чекають по черзі для потоку працівника, щоб порожній власний запис, не знаходити роботи в інших робочих роботах, знайти запит на очікування в черзі для подачі та розпочати відправлення.
  • Інші теми можуть робити те ж саме. Тобто вони підбирають один запит за один раз, закінчають цей запит і допомагають завершити інші запити, перш ніж шукати новий запит.
  • Оскільки все більше запитів заповнюють чергу подання, вони створюють резервну копію. Це може призвести до значного відставання, оскільки неможливо затримати будь-який запит, неможливо скасувати синхронні запити, а також не може готувати чергу на гарячий запит. (Робота-викрадення, реалізована за допомогою декретів FIFO / LIFO, не сприяє внесенню запитів безпосередньо в робочу службу).
  • Отже, для багаторазових подань є мало, якщо такі є, користь для системи F / J. Використання однієї гілки за запитом (як-от пул потоків) без обробки часто є більш ефективним для пропускної спроможності. Не вірте? Спробуйте самі. (Ви можете завантажити вихідний код демо-версії F / J або Thread Pool внизу.)

Цей недолік лише кваліфікує систему F / J для місця в класі, а не як ядро ​​Java? паралельні обчислення.

Не API

F / J Framework є частиною Специфікації API SE7, але в пакеті не вистачає «характеристик хорошого API» (Джошуа Блох). Пакет фактично є незалежним об’єктом, що маскує як API.

Жоден з базових класів у пакунку F / J не може жити самостійно, і основні класи не мають використання поза рамками. Основний клас пулу розширює AbstractExecutorService, що робить рамку сервером додатків — незалежною сутністю.

Інші класи в JDK розширюють Службу Виконавця (ThreadPoolExecutor, для одного), але вони не можуть жити окремо. Ці класи є компонентами в користувальницьких служб додатків; вони не є послугами самі по собі.

Система F / J є самостійним об’єктом. Більшість методів базової підтримки є остаточними, щоб запобігти перевагам. Класи базового пакета є сервером для себе, вони не є індивідуальними API для програмістів для розширення та побудови іншої служби.

Явним прикладом незалежності є не Java? Мови, такі як Scala, Akka, Clojure, X10, Fortress та інші, використовують рамки без розширення.

Незалежний сервер не належить до JDK.

 Висновок

Фундаментальний модуль F / J відсутній як API

  • Він має дефіцит «характеристик хорошого API» (Джошуа Блох)

Система F / J істотно неадекватна як служба додатків

  • Вона доступна лише як вбудований сервер, немає доступу до віддаленого об’єкта, такого як RMI
  • Це рекомендовано лише для сукупних операцій з даними.
  • Це рекомендується лише для користувачів з дуже великими структурами даних (humongous масиви)
  • Це корисно лише для машин з великими процесорами (рекомендовано 16+)
  • Це корисно лише для одного запиту за один раз
  • Це корисно лише для строго обмеженої обробки (рекомендовано)
    • повинен бути простий (від 100 до 10000 базових обчислювальних кроків у методі обчислень)
    • Обчислити тільки інтенсивний код
    • немає блокування
    • немає вводу / виводу
    • немає синхронізації
  • Вона не веде журналювання або сповіщення
  • Вона не має помилок / стійла відновлення
  • Вона не має можливості відображати / змінювати поточний статус виконання
  • Він спирається на академічну коректність, а не на ремонтопридатність
  • Це не має сенсу
  • Його багатозадачність несправна
  • Це неефективно
  • Це не може бути масштабним для сотень процесорів
  • Це складно з точки зору незрозумілості
  • Немає посібника користувача, просто JavaDoc

Незначні переваги системи F / J не переважають

  • роздути цей експеримент додає до Java? Час запуску для користувачів, які не приєднались до системи
  • обмеження для розробників, які прагнуть паралелізувати своє програмне забезпечення, особливо з JDK1.8

Система F / J — це неадекватний академічний експеримент, заснований на дослідницькому документі, а не легкий механізм. Це не належить до JDK.

Список літератури

Завантажте вихідний код статті тут.

Завантажте проект розсіювання з SourceForge.net, проект: TymeacDSE

Java Fork / Join Framework — Дуг Лі

Частина друга цієї серії Java Parallel Calamity

http://coopsoft.com/ar/Calamity2Article.html

Частина третя цієї серії — Java? Паралельна помилка

http://coopsoft.com/ar/Calamity3Article.html

 

JDK1.8 Паралельна схема хешу в списку паралельних інтересів

http://cs.oswego.edu/pipermail/concurrency-interest/2012-August/009711.html

JDK1.8 Розширення Java пропозиції 103

http://openjdk.java.net/jeps/103

Як створити хороший API та чому це означає — Джошуа Блох

Коли використовувати ForkJoinPool vs ExecutorService — JavaWorld

http://www.javaworld.com/javaworld/jw-10-2011/111004-jtip-recursion-in-java-7.html

700 продовжувальних ниток —

http://stackoverflow.com/questions/10797568/what-determines-the-number-of-threads-ajava-forkjoinpool-створює

Теорія та практика Java: дотримуйтесь вилки в ній, частина 1

http://www.ibm.com/developerworks/java/library/j-jtp11137.html

Сайт Cilk-Plus — http://software.intel.com/en-us/articles/intel-cilk-plus/

Сайт jCilk на базі Java — http://supertech.csail.mit.edu/jCilkImp.html

Сайт JRockit — http://www.oracle.com/technetwork/middleware/jrockit/overview/index.html

 

Робоча крадіжка документів:

www.cs.rice.edu/~vs3/PDF/ppopp.09/p45-michael.pdf

www.eecis.udel.edu/~cavazos/cisc879-spring2008/Brice.pdf

home.ifi.uio.no/paalh/publications/files/mucocos2010.pdf

Written by