Към съдържанието

Паралелни работници

Greph разпределя текстовите и AST сканиранията между пул от работници, когато обемът работа е достатъчен, за да оправдае разходите. Пулът е базиран на pcntl_fork() и преминава към изпълнение в процеса, когато ext-pcntl не е наличен (Windows, някои PaaS среди, ограничен хостинг).

Активиране на паралелни сканирания

Задайте -j N на CLI или jobs: N в съответния обект с опции:

Обвивка
./vendor/bin/greph -F -j 8 "function" src
./vendor/bin/greph -p '$obj->$method($$$ARGS)' -j 4 src
./vendor/bin/rg --threads 8 -F "function" src
./vendor/bin/sg run --threads 8 --pattern '$obj->$method($$$ARGS)' src
PHP
use Greph\Greph;
use Greph\Text\TextSearchOptions;

Greph::searchText(
    'function',
    'src',
    new TextSearchOptions(fixedString: true, jobs: 8),
);

Кога се включва паралелната обработка

Greph не изпълнява всичко паралелно безусловно. Стартирането на N процеса и обменът на резултатите им чрез канали създават разходи, които при малки списъци с файлове надвишават цената на самото търсене. Вместо това фасадата изчислява праг според броя задачи, режима на търсене и формата на шаблона. Само списъците с файлове над прага се изпращат към пула от работници.

Текущите евристики (в Greph\Greph::shouldUseTextWorkers и свързаните с него компоненти):

  • Изпълненията с една задача (-j 1) винаги се изпълняват в процеса.
  • Обикновените текстови сканирания изискват приблизително jobs * 2_000 файла, преди да се включи пулът.
  • Режимите за брой, файлове със съвпадения и файлове без съвпадения понижават прага до около jobs * 750, защото обработката на файл е по-евтина.
  • Кратките шаблони с фиксиран низ във формата на идентификатор повишават прага до около jobs * 4_000, защото бързият път за буквални низове вече е толкова евтин, че стартирането на процеси рядко си струва.
  • Търсенето и замяната в AST използват прага jobs * 750.

Тези числа са евристични, а не гарантирани стойности. Те са настроени спрямо бенчмарк корпуса WordPress и може да бъдат преразгледани.

Как работи пулът

Greph\Parallel\WorkSplitter разпределя списъка с файлове между N части. Greph\Parallel\WorkerPool стартира отделен работен процес за всяка част; всеки работник изпълнява същата функция върху своя дял, а Greph\Parallel\ResultCollector прочита сериализираните резултати през отделна двойка сокети Unix за всеки работник. Родителският процес изчаква всички работници, след което обединява и сортира отново общия набор от резултати, така че редът на изхода да е стабилен независимо от разпределението на работата.

За текстовия режим пулът от работници използва персонализиран кодек за предаване по мрежата (Greph\Text\TextResultCodec), за да запази сериализирания полезен товар компактен. Режимът AST използва стандартния serialize() на PHP.

Когато pcntl не е наличен

Ако pcntl_fork не може да бъде извикана (Windows, компилации на PHP с усилена защита), пулът прозрачно преминава към изпълнение на всяка част в процеса. Резултатът е същият като при -j 1. Greph не извежда грешка, а просто се изпълнява в една нишка.

Можете да проверите това по време на изпълнение с function_exists('pcntl_fork').

Съвети за настройване

  • Започнете със -j, зададен на половината от броя на физическите ядра, и го увеличавайте, докато подобренията спрат.
  • При търсене с фиксиран низ в малки хранилища един процес обикновено е по-бърз от всяка паралелна настройка.
  • Няма публикуван бенчмарк за паралелно търсене или замяна в AST. Измерете производителността върху собственото си дърво, преди да изберете броя задачи.
  • Редовете „Режим на сканиране: паралелен текст“ в README (работници: 1, 2 и 4, корпус WordPress) не измерват пула: търсят краткия буквален низ function, чийто праг от jobs * 4_000 файла е над размера на корпуса, така че всеки ред се изпълнява в процеса (#8).

Ограничения

  • Пулът понастоящем не поддържа разпределяне на работа от неангажирани работници. Ако една част е значително по-тежка от останалите, пулът изчаква най-бавния работник.
  • Резултатите от работниците се буферират, докато всички приключат. Паралелният режим не поддържа поточно извеждане от продължително сканиране (както rg --json предава събития).
  • След обединяването родителският процес сортира резултатите отново, затова пулът от работници не намалява пиковото използване на паметта спрямо сканирането в един процес.

Тези ограничения са приемливи за работните натоварвания, към които е насочен Greph (интерактивно търсене в код, цикли на агенти, CI задачи върху моментни снимки). Ще бъдат преразгледани, ако профилирането покаже, че са пречка при реални корпуси.