На мою думку, це казкове запитання про інтерв'ю - принаймні припускаючи, що (1) від кандидата очікується глибоке знання нитки, і (2) інтерв'юер також має глибокі знання та використовує питання для дослідження кандидата. Завжди можливо, що інтерв'юер шукав конкретну, вузьку відповідь, але грамотний інтерв'юер повинен шукати наступне:
- Здатність відрізняти абстрактні поняття від конкретної реалізації. Я кидаю це в основному як мета-коментар до деяких коментарів. Ні, немає сенсу обробляти єдиний список слів таким чином. Однак важливим є абстрактне поняття конвеєра операцій, який може охоплювати кілька машин різної спроможності.
- На мій досвід (майже 30 років розповсюджених, багатопроцесових та багатопотокових програм), розповсюдження твору - це не найважча частина. Збір результатів та узгодження незалежних процесів - це місце, де трапляється більшість помилок з прошивкою (знову ж таки, на мій досвід). Перенаправивши проблему до простого ланцюжка, інтерв'юер може побачити, наскільки добре думає кандидат про координацію. Крім того, інтерв'юер має можливість задавати всілякі подальші запитання, такі як "Гаразд, що робити, якщо кожна нитка повинна направити своє слово в інший потік для реконструкції".
- Чи думає кандидат про те, як модель пам'яті процесора може вплинути на впровадження? Якщо результати однієї операції ніколи не стираються з кешу L1, це помилка, навіть якщо немає явної одночасності.
- Чи відокремлює кандидат введення нитки від логіки програми?
Цей останній пункт є, на мою думку, найважливішим. Знову-таки, виходячи з мого досвіду, налагоджувати потоковий код стає експоненціально складніше, якщо введення різьби змішується з логікою програми (просто подивіться на всі питання Swing на SO для прикладів). Я вважаю, що найкращий багатопотоковий код пишеться як автономний однопотоковий код з чітко визначеними передачами передач.
Зважаючи на це, мій підхід полягав би в тому, щоб дати кожному потоку дві черги: одну для введення, другу для виводу. Блок потоку, читаючи вхідну чергу, знімає перше слово з рядка і передає решту рядка у свою вихідну чергу. Деякі особливості такого підходу:
- Код програми відповідає за читання черги, щось робити з даними та запис черги. Не важливо, багатопотокова чи ні, чи черга є чергою в пам'яті на одній машині чи чергою на основі TCP між машинами, які живуть на різних сторонах світу.
- Оскільки код програми написаний як би однопотоковий, його можна перевірити детерміновано, без необхідності багато лісів.
- Під час фази виконання коду програми належить обробляється рядок. При цьому не потрібно дбати про синхронізацію з одночасно виконаними потоками.
Однак, є багато сірих ділянок, які може перевірити компетентний інтерв'ю:
- "Гаразд, але ми хочемо побачити ваші знання про примітиви одночасності; чи можете ви реалізувати блокуючу чергу?" Ваша перша відповідь, звичайно, повинна полягати в тому, що ви будете використовувати заздалегідь вбудовану чергу блокування з вашої платформи на вибір. Однак якщо ви розумієте потоки, ви можете створити реалізацію черги під десяток рядків коду, використовуючи будь-які примітиви синхронізації, які підтримує ваша платформа.
- "Що робити, якщо один крок у процесі займає дуже довго?" Вам слід подумати про те, чи потрібно обмежена чи необмежена черга виводу, як ви можете обробляти помилки та впливати на загальну пропускну здатність, якщо у вас затримка.
- Як ефективно зав'язувати вихідний рядок. Це не обов'язково проблема, якщо ви маєте справу з чергами в пам'яті, але це може бути проблемою, якщо ви переходите між машинами. Ви також можете досліджувати обгортки лише для читання, розташовані поверх основного масиву незмінних байтів.
Нарешті, якщо у вас є досвід одночасного програмування, ви можете поговорити про деякі рамки (наприклад, Akka для Java / Scala), які вже відповідають цій моделі.