Паралельність: Як ви підходите до розробки та налагоджуєте реалізацію?


37

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

Однак я вважаю, що існує дуже мало інструментів, які допоможуть візуалізувати те, що ви маєте намір зробити, і підтвердити, що ви принаймні близькі до свого початкового бачення. Налагодження паралельного коду може бути кошмаром з мовами, які не розроблені для одночасності (наприклад, C / C ++, C #, Java тощо). Зокрема, неможливо відтворити умови, які легко трапляються в одній системі у вашому середовищі розробки.

Отже, які ваші підходи до проектування системи, що стосується паралельності та паралельної обробки? Приклади:

  • Як ви зрозумієте, що можна зробити одночасно проти того, що має бути послідовним?
  • Як ви відтворюєте умови помилок і переглядаєте, що відбувається під час виконання програми?
  • Як ви візуалізуєте взаємодію між різними сумісними частинами програми?

У мене є відповіді на деякі з них, але я також хотів би дізнатися трохи більше.

Редагувати

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

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

Мета для Баунті

Не кажи мені, що я повинен робити. Я це вже маю під контролем. Скажи мені, що ти робиш. Розкажи, як ти вирішуєш ці проблеми.


Це хороше питання - багато можливої ​​глибини. Я також здобув хороший досвід роботи з багатопотоковими програмами на Java, але хотів би дізнатися більше.
Майкл К

Поки ми маємо кілька хороших відповідей. Хтось хоче зайнятись ножом у тому, що ви хочете, щоб вам допомогли в цій галузі?
Берін Лорич

Налагоджувач TotalView для одночасного кодування є досить корисним інструментом, хоча трохи вивчає криву навчання - totalviewtech.com/products/totalview.html
Fanatic23

Можливо, реєстрація може допомогти вам у двох останніх запитаннях.
Амір Резай

Що я шукаю - це процеси людей. Це сфери, де інструменти, якими я користувався, є неадекватними, але можуть зробити роботу. Мене менше турбує цитування чужої статті та більше стурбований методологією тут.
Берін Лорич

Відповіді:


11

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

Багато кращих програмістів, яких я знаю, не закінчили університет. Щодо мене, я вивчав філософію.

C / C ++, C #, Java тощо). Зокрема, неможливо відтворити умови, які легко трапляються в одній системі у вашому середовищі розробки.

так

Як ви зрозумієте, що можна зробити одночасно проти того, що має бути послідовним?

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

Коли ми стикалися з цією проблемою, ми завжди знаходили спосіб обмеження видимості одночасних об'єктів на непорушні.

Нещодавно я виявив "Акторів" в масштабі "скала" і побачив, що мої старі рішення - це свого роду "мініактори", набагато менш потужні, ніж скала. Тож моя пропозиція - почати звідти.

Ще одна пропозиція - пропустити якомога більше проблем: наприклад, ми використовуємо централізований кеш (теракота) замість того, щоб зберігати карти в пам’яті, використовуючи зворотні звороти внутрішнього класу замість синхронізованих методів, надсилаючи повідомлення замість написання спільної пам'яті тощо.

З scala все одно набагато простіше.

Як ви відтворюєте умови помилок і переглядаєте, що відбувається під час виконання програми?

Тут немає реальної відповіді. У нас є кілька тестів на конкурентоспроможність, і ми маємо набір тестових навантажень, щоб підкреслити додаток наскільки це можливо.

Як ви візуалізуєте взаємодію між різними сумісними частинами програми?

Знову немає реальної відповіді: ми проектуємо нашу Метафору на дошці і намагаємось упевнитись, що немає конфліктів на архітектурній стороні.

Для Arch тут я маю на увазі визначення Ніла Форда: Sw Architecture - це все, що згодом буде дуже важко змінити.

програмування змушує мене вважати, що вам потрібен інший спосіб мислення, ніж ви робите з послідовним програмуванням.

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


6

Мені все стосується даних. Розбийте свої дані правильно, а паралельна обробка проста. Всі проблеми із утриманням, тупиками тощо.

Я знаю, що це не єдиний спосіб паралелізації, але для мене далеко не найкорисніший.

Для ілюстрації (не дуже швидка) історія:

Я працював над великою фінансовою системою (контроль ринку цінних паперів) у 2007–2009 рр., І обсяг даних був дуже великий. Для ілюстрації, всі розрахунки, зроблені на одному єдиному обліковому записі клієнта, займали приблизно 1–3 секунди на їх середній робочій станції, а облікових записів було більше 30 тис. Щовечора закриття системи було великим болем для користувачів (зазвичай це більше 6 годин обробки, без жодних помилок для них).

Вивчення проблеми надалі показало, що ми могли б паралелізувати обчислення серед декількох комп'ютерів, але ми все ще мали б велике вузьке місце на старому сервері баз даних (сервер SQL 2000, що емулює SQL 6.5).

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

1) Один-єдиний виробник, відповідальний за читання бази даних або запис на ній послідовно. Тут не допускається жодна паралельність. Виробник підготував чергу для споживачів. База даних належала виключно цьому виробнику.

2) Кілька споживачів, на декількох машинах. Кожен із споживачів отримав цілий пакет даних із черги, готовий до обчислення. Кожна операція deqeue синхронізована.

3) Після підрахунку кожен споживач надсилає дані виробнику в синхронізовану чергу пам’яті виробнику, щоб зберегти дані.

Було кілька пунктів пропуску, кілька механізмів, щоб гарантувати, що транзакції були правильно збережені (жоден не залишився позаду), але ціла робота того вартувала. Врешті-решт, розрахунки, розповсюджені серед 10 комп’ютерів (плюс комп'ютер виробника / черги), зменшили час закриття всієї системи до 15 хвилин.

Просто усунення проблем із утриманням, спричинених поганим управлінням паралельністю SQL 6.5, дало нам велику перевагу. Решта була досить лінійною, кожен новий комп'ютер, доданий до "сітки", зменшував час обробки, поки ми не досягли "максимальної ефективності" послідовних операцій читання / запису в базі даних.


2

Робота в багатопотоковому середовищі - важка і потребує дисципліни кодування. Вам потрібно дотримуватися належних рекомендацій щодо зняття блокування, звільнення блокування, доступу до глобальних змінних тощо.

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

* How do you figure out what can be made concurrent vs. what has to be sequential?

Використовуйте паралельність для

1) Опитування: - потрібна нитка, щоб постійно щось запитувати або регулярно надсилати оновлення. (Такі поняття, як біт серця, який регулярно надсилає деякі дані на центральний сервер, щоб сказати, що я живий.)

2) Операції, які мають важкий введення / виведення, можуть бути виконані паралельно. Найкращий приклад - лісоруб. Нитка реєстратора може бути окремою ниткою.

3) Подібні завдання за різними даними. Якщо є якесь завдання, яке трапляється за різними даними, але за своєю суттю дуже схоже, різні потоки можуть це зробити. Найкращим прикладом будуть запити сервера.

І, звичайно, багато інших люблять це в залежності від застосування.

* How do you reproduce error conditions and view what is happening as the application executes?

Використання журналів та налагодження друку в журналах. Спробуйте записати також ідентифікатор потоку, щоб ви могли бачити, що відбувається в кожному потоці.
Один із способів створити умову помилки - поставити навмисне затримку (в коді налагодження) в місцях, де ви думаєте, що проблема виникає, і насильно зупинити цю нитку. Подібні речі можна робити і в налагоджувачах, але я цього ще не робив.

* How do you visualize the interactions between the different concurrent parts of the application?

Покладіть колоди у свої замки, щоб ви дізналися, хто блокує, що і коли, а хто намагався заблокувати. Як я вже говорив раніше, спробуйте вставити ідентифікатор потоку в журнал, щоб зрозуміти, що відбувається в кожному потоці.

Це лише моя порада, яка приблизно три роки працює над багатопотоковим додатком, і сподіваюся, що це допоможе.


2
  • Як ви зрозумієте, що можна зробити одночасно проти того, що має бути послідовним?

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

Співпрацюючи з Ерланг, мені дуже подобається концепція використання асинхронного передавання повідомлень та акторської моделі для одночасності - це інтуїтивно зрозуміло, ефективно та чисто.

Відсутнє розуміння паралельності актора

Акторська модель складається з кількох ключових принципів:

  • Немає спільного стану
  • Легкі процеси
  • Асинхронна передача повідомлень
  • Поштові скриньки для буфера вхідних повідомлень
  • Обробка поштової скриньки із узгодженням шаблону

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

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

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

Ця модель не є ексклюзивною для Ерланг, навіть у світі Java та .NET існують способи її створення - я би поглянув на параметри виконання та координації (CCR) та Relang (є також Jetlang для Java).

  • Як ви відтворюєте умови помилок і переглядаєте, що відбувається під час виконання програми?

На мій досвід, єдине, що я можу зробити, - це зобов'язання відстежувати / реєструвати все. Кожен процес / потік повинен мати ідентифікатор, і кожна нова одиниця роботи повинна мати ідентифікатор кореляції. Вам потрібно вміти переглядати ваші журнали та відстежувати, що саме оброблялось, і коли - я не бачив жодної магії, яка б це усунула.

  • Як ви візуалізуєте взаємодію між різними сумісними частинами програми?

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


1

- Мої відповіді специфічні для MS / Visual Studio -

Як ви зрозумієте, що можна зробити одночасно проти того, що має бути послідовним?

Це займе знання домену, тут не буде жодної заяви про покриття.

Як ви відтворюєте умови помилок і переглядаєте, що відбувається під час виконання програми?

Багато ведення лісозаготівлі, можливість включення / вимкнення / вимкнення вхідних даних у виробничих додатках, щоб заробити це у виробництві. VS2010 Intellitrace , мабуть, може допомогти у цьому, але я його ще не використовував.

Як ви візуалізуєте взаємодію між різними сумісними частинами програми?

Я не маю гарної відповіді на це, хотів би її побачити.


Журнал змінить спосіб виконання коду і, таким чином, може призвести до помилки, яку ви не з’явилися.
Матвій

1

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

Я намагаюсь, наскільки це можливо, реалізувати замки з ідеєю, що зрештою, справді практичне програмування без блокування може стати для мене реальністю. Під блокуванням я не маю на увазі взаємне виключення, я просто маю на увазі процес, який реалізує безпечну сумісність без необхідності арбітражу. На практиці я маю на увазі те, що легше перенести, ніж було реалізовано. У мене також дуже мало формальних тренувань з CS, але я вважаю, що мені це можна побажати :)

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

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

Потім знову киньте туди "розподілених" і арбітраж стає необхідним. У вас є конкретний приклад?


Для уточнення мого твердження C не був розроблений спеціально для паралельності і навколо нього. Це на відміну від таких мов, як Go, Erlang та Scala, які були розроблені явно з урахуванням одночасності. Я не збирався сказати, що ви не можете
погодитися

1

Як ви відтворюєте умови помилок і переглядаєте, що відбувається під час виконання програми?

Як ви візуалізуєте взаємодію між різними сумісними частинами програми?

На основі мого досвіду відповідь на ці два аспекти виглядає наступним чином:

Розподілений трасування

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

Розподілене трасування завдячує своїм джерелом (звичайно) розподіленим системам, які за визначенням є асинхронними та сильно сумісними. Розподілена система з розподіленим трасуванням дозволяє людям:

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

Наслідками розподіленого трасування є:

  1. Він додає накладні витрати на всі ваші паралельні процеси, оскільки він перетворюється на більше коду для виконання та надсилання потенційно через мережу. У деяких випадках ця накладні витрати дуже важливі - навіть Google використовує лише їх систему трасування Dapper лише для невеликого підмножини всіх запитів, щоб не зруйнувати досвід користувачів.

  2. Існує багато різних інструментів, не всі з яких є взаємодіючими між собою. Це дещо покращено такими стандартами, як OpenTracing, але не повністю вирішеними.

  3. Це нічого не говорить про спільні ресурси та їх поточний статус. Можливо, ви зможете здогадатися на основі коду програми та того, що вам показує графік, але це не корисний інструмент у цьому плані.

  4. Поточні інструменти передбачають, що у вас є запасний обсяг пам’яті та місця. Розміщення сервера таймсері може бути недешевим, залежно від ваших обмежень.

Помилка відстеження програмного забезпечення

Я посилаюсь на Sentry вище перш за все тому, що це найпоширеніший інструмент там, і з поважної причини - програмне забезпечення для відстеження помилок, наприклад виконання програми Hijack Hent, щоб одночасно пересилати стек стека помилок, що виникають на центральний сервер.

Чиста перевага такого виділеного програмного забезпечення у паралельному коді:

  1. Повторні помилки не дублюються . Іншими словами, якщо одна чи кілька одночасних систем стикаються з тим самим винятком, Sentry збільшить звіт про інцидент, але не подасть дві копії інциденту.

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

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

  1. Ви можете модифікувати це програмне забезпечення для обробки помилок, щоб забезпечити додаткові деталі з винятками під час виконання. Які відкриті ресурси мав цей процес? Чи є спільний ресурс, який тримав цей процес? Який користувач відчув цю проблему?

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

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

До недоліків такого програмного забезпечення можна віднести:

  1. Як і все, вони додають об'ємність. Наприклад, ви не хочете такої системи на вбудованому обладнання. Я настійно рекомендую пробний запуск такого програмного забезпечення, порівнюючи просте виконання з і без нього вибірки протягом декількох сотень запусків на простої машини.

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

  3. Вони можуть бути підвищені як ризик для безпеки, оскільки багато хто з цих систем по суті є закритим джерелом. У таких випадках докладіть належних зусиль у їх дослідженні або, якщо бажаєте, прокатуйте свої власні.

  4. Вони не завжди можуть дати тобі потрібну інформацію. Це ризик при всіх спробах додати видимість.

  5. Більшість цих сервісів були розроблені для дуже одночасних веб-додатків, тому не кожен інструмент може бути ідеальним для вашого випадку використання.

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

Деякі додаткові пропозиції

Я витратив більше часу, ніж я дбаю про виправлення коду людьми, які намагалися вирішити паралельні проблеми жахливими способами. Кожного разу я виявляв випадки, коли такі речі можуть значно покращити досвід розробника (що так само важливо, як і досвід користувачів):

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

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

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

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

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

Деякі з цих інструментів постачаються в комплекті з мовами - наприклад, Rust гарантує, що ваш код не матиме гоночних умов під час компіляції, тоді як Go має вбудований детектор тупикового зв'язку, який також працює під час компіляції. Якщо ви зможете наздогнати проблеми, перш ніж потрапити на виробництво, це завжди виграш.

Загальне правило: проектування для відмов у паралельних системах . Передбачайте, що загальні служби вийдуть з ладу або зламаються. Це стосується навіть коду, який не поширюється на машинах - паралельний код на одній машині може покладатися на зовнішні залежності (наприклад, загальнодоступний файл журналу, сервер Redis, проклятий сервер MySQL), який може зникнути або видалитись у будь-який час .

Найкращий спосіб зробити це - час від часу перевіряти стан заявки - провести перевірку стану здоров’я для кожної послуги та переконатись, що споживачі цієї служби повідомляються про погане самопочуття. Сучасні інструменти для контейнерів, такі як Docker, роблять це досить добре, і їх слід використовувати для роботи з пісочницею.

Як ви зрозумієте, що можна зробити одночасно, а що можна зробити послідовним?

Один з найбільших уроків, який я навчився, працюючи над системою, що суттєво поєднується, це такий: ви ніколи не можете мати достатню кількість показників . Метрики повинні керувати абсолютно всім у вашій програмі - ви не інженер, якщо ви все не вимірюєте.

Без показників ви не можете зробити кілька дуже важливих речей:

  1. Оцініть різницю, внесену змінами в систему. Якщо ви не знаєте, чи ручка налаштування A, зроблений показник B, знижується, а показник C знизиться, ви не знаєте, як виправити вашу систему, коли люди несподівано натиснуть злоякісний код на вашу систему (і вони підштовхнуть код до вашої системи) .

  2. Зрозумійте, що вам потрібно зробити далі, щоб покращити речі. Поки ви не знаєте, що у додатків не вистачає пам'яті, ви не можете зрозуміти, чи потрібно вам більше пам’яті чи купувати більше диска для своїх серверів.

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

Але, безумовно, є кілька основних правил:

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

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

Один потік може зробити багато роботи вводу / виводу. Але для повного використання одночасності вашого обладнання використовуйте потокові пули, які разом займають усі ядра. У наведеному вище прикладі запуск п'яти процесів Python (кожен з яких може використовувати ядро ​​на шестиядерній машині) тільки для роботи з процесором, а шостий потік Python тільки для роботи вводу / виводу буде масштабуватися набагато швидше, ніж ви думаєте.

Єдиний спосіб скористатися паралельністю CPU - це спеціалізована нитка. Один потік часто досить хороший для великої роботи, пов'язаної з входом / виводом. Ось чому веб-сервери, керовані подіями на зразок Nginx, краще (вони виконують суто роботу, пов'язану з входом / виводом), ніж Apache (яка пов'язує роботу, пов'язану введення / виводу з чимось, що вимагає процесора та запускає процес за запитом), але чому використовувати Node для виконання десятки тисяч розрахунків GPU, отриманих паралельно, - жахлива ідея.


0

Що ж, для процесу верифікації під час проектування великої одночасної системи я схильний протестувати модель за допомогою LTSA - Labeled Transition System Analyzer . Він був розроблений моїм старим репетитором, який є чимось ветераном у галузі кон'юнктури і зараз є керівником обчислювальної техніки в Imperial.

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


0

Як ви зрозумієте, що можна зробити одночасно проти того, що має бути послідовним?

Практично кожна річ, яку ви пишете, може скористатися паралельністю, особливо випадком використання "поділити підкорити". Набагато краще питання - що має бути одночасно?

Жозеф Альбахарі в нитці C # перелічить п'ять загальних застосувань.

Багатопоточне читання має безліч застосувань; ось найпоширеніші:

Підтримка чуйного інтерфейсу користувача

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

Ефективне використання інакше заблокованого процесора

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

Паралельне програмування

Код, який виконує інтенсивні обчислення, може виконуватись швидше на багатоядерних або багатопроцесорних комп'ютерах, якщо робоче навантаження поділяється між декількома потоками в стратегії "ділити-перемагай" (див. Частина 5).

Спекулятивне виконання

На багатоядерних машинах іноді можна покращити продуктивність, передбачивши щось, що може знадобитися зробити, а потім зробити це достроково. LINQPad використовує цю методику для прискорення створення нових запитів. Різновидом є паралельне виконання декількох різних алгоритмів, які вирішують одне і те ж завдання. Незалежно від того, хто з них закінчує першу «перемогу» - це ефективно, коли ви не можете знати достроково, який алгоритм виконає найшвидше.

Дозволяє одночасно обробляти запити

На сервері запити клієнтів можуть надходити одночасно, тому їх потрібно обробляти паралельно (.NET Framework створює потоки для цього автоматично, якщо ви використовуєте ASP.NET, WCF, веб-сервіси чи видалення). Це також може бути корисно для клієнта (наприклад, обробка однорангових мереж - або навіть декілька запитів від користувача).

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

Як ви відтворюєте умови помилок і переглядаєте, що відбувається під час виконання програми?

Якщо ви використовуєте .NET і писали випадки використання, ви можете використовувати CHESS, який може відтворити конкретні умови переплетення потоку, що дозволяє перевірити виправлення.

Як ви візуалізуєте взаємодію між різними сумісними частинами програми?

Це залежить від контексту. Для робочих сценаріїв я думаю про керівника-підлеглого. Manger каже підлеглому щось зробити і чекає оновлення статусу.

Для одночасних незв’язаних завдань я думаю, що ліфти чи машини в окремих смугах руху.

Для синхронізації я інколи думаю про світлофори або повороти.

Крім того, якщо ви використовуєте C # 4.0, ви можете поглянути на бібліотеку паралельних завдань


0

Моя відповідь на ці питання:

  • Як ви зрозумієте, що можна зробити одночасно проти того, що має бути послідовним?

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

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

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

  • Як ви відтворюєте умови помилок і переглядаєте, що відбувається під час виконання програми?

Я не експерт у цьому питанні, але думаю, що для паралельних систем це не правильний підхід. Слід обрати теоретичний підхід, шукаючи 4 вимоги, що стосуються тупикових ситуацій у критичних областях:

  1. Непередбачуваність
  2. Тримай і чекай
  3. Мобільне виключення
  4. Круговий ланцюг

    • Як ви візуалізуєте взаємодію між різними сумісними частинами програми?

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


0

Я буду тупим. Я обожнюю інструменти. Я використовую багато інструментів. Мій перший крок - прокласти намічені шляхи для протікання стану. Наступним моїм кроком є ​​спробувати і зрозуміти, чи варто це чи якщо необхідний потік інформації буде надто часто видавати код послідовним. Потім я спробую скласти кілька простих моделей. Вони можуть варіюватися від масиву грубих скульптур зубочисток до простих подібних прикладів у python. Далі я переглядаю пару моїх улюблених книг, як маленька книжка семафорів, і бачу, чи хтось уже придумав краще рішення моєї проблеми.

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

Нарешті, я починаю кодування. Я намагаюся спочатку зробити це дуже простим. Просто шлях коду, нічого фантазійного. Перемістіть якомога менше штату. Уникайте написань. Уникайте читання, яке може суперечити запису. Уникайте, перш за все, записів, які можуть суперечити написаним. Дуже легко виявити, що ти маєш позитивно токсичну кількість цього, і що твоє прекрасне рішення раптом трохи більше, ніж серійний підхід, який обробляє кеш-пам'ять.

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

Нарешті, інструменти. Налагодження дуже важко. Я використовую valgrind \ callgrind на Linux у поєднанні з PIN-кодом та паралельними студіями на windows. Не намагайтеся вручну налагоджувати цей матеріал. Ви, мабуть, можете. Але ви, мабуть, хочете, щоб цього не зробили. Десять годин освоєння деяких потужних інструментів, а деякі хороші моделі заощадять вас на сотні годин пізніше.

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

У підсумку:
Початок:
Think
Talk
Test
Write просто
Read
Test
Write
Debug
GOTO Begin

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.