Как написать многопоточный алгоритм альфа-бета-поиска?

Я пытаюсь создать шахматный движок, используя альфа-бета-минимаксный алгоритм поиска, но код работает слишком медленно. Я сделал все оптимизации, о которых только мог подумать, но в одном потоке он все еще очень медленный. Я просмотрел исходный код некоторых других движков, чтобы увидеть, как они это делают, и вики по шахматному программированию (https://www.chessprogramming.org/Parallel_Search#Parallel_Alpha-Beta), но код выше моего уровня, и я не понимаю их. Я также не смог найти никаких письменных источников или фрагментов кода.

Может ли кто-нибудь объяснить, как эффективно реализовать многопоточность в алгоритме альфа-бета-поиска? Спасибо.

Насколько медленно это медленно? На каком языке вы это пишете? Какие функции вы реализовали?

eligolf 20.03.2022 17:47

Около 3 секунд для глубины 4. На любую глубину, превышающую эту, требуется несколько минут. Он написан на C# для игрового движка Unity. Это просто минимакс с обрезкой альфа-бета. Пока нет транспозиции или порядка перемещения.

mrinin 20.03.2022 18:52

Какое представительство в совете вы используете? 2D-массив, 1D-массив, битборды? Если любой из первых двух, то ваша производительность является разумной. Сначала подумайте о том, чтобы сделать больше обычных оптимизаций, прежде чем делать многопоточность, многопоточность будет трудной для отладки. Порядок перемещения — это золото, и его очень легко реализовать. Также попробуйте отсечение нулевого хода, поиск PVS и, возможно, какое-то другое сокращение. Вы копируете доску или делаете/отменяете ход? Сделайте последнее. Много информации о шахматном программировании, на которую вы ссылались, поищите там больше оптимизаций.

eligolf 21.03.2022 06:40

Пожалуйста, уточните вашу конкретную проблему или предоставьте дополнительную информацию, чтобы выделить именно то, что вам нужно. Как сейчас написано, трудно точно сказать, о чем вы спрашиваете.

Community 21.03.2022 16:38
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
69
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Альфа-бета по своей сути является последовательным алгоритмом, так как ваши альфа- и бета-значения постоянно обновляются в ходе поиска, а отсечки определяются на основе этих значений. По этой причине получить какое-либо ускорение за счет увеличения количества потоков очень сложно, и чем больше потоков вы бросите, тем меньше будет выигрыш.

Однако есть еще несколько способов сделать это, большинство из них довольно сложны и крайне плохо масштабируются при большем количестве потоков. Алгоритм перехода раньше был концепцией ожидания Young Brothers, это довольно сложный алгоритм, и он использовался, например, Stockfish до нескольких лет назад. Однако с увеличением количества ядер, доступных на современных компьютерах, масштабирование было очень плохим, а код очень сложным. Сегодня большинство современных движков используют то, что называется Lazy SMP. Этот алгоритм настолько прост, насколько это возможно, и масштабируется лучше, чем другие.

В ленивом SMP все, что вам нужно сделать, это запустить точно такой же поиск, как и обычно, только в нескольких потоках. Он зависит от наличия работающей таблицы транспонирования, через которую потоки взаимодействуют друг с другом. Потоки никогда не будут точно синхронизированы, и случайность приведет к тому, что каждый поток будет исследовать несколько разные части дерева поиска, а затем сохранять свои результаты в таблице транспонирования, где они могут быть использованы другим потоком. Конечно, каждый поток выполняет много повторяющейся работы, однако это все же лучше, чем пытаться умничать, разделяя работу и замедляя алгоритм, и это особенно верно, когда вы начинаете увеличивать количество потоков.

Я рекомендую вам заглянуть на вики по шахматному программированию, где вы даже можете найти псевдокод того, как это реализовать. https://www.chessprogramming.org/Lazy_SMP

Хотя я также должен отметить, что если то, что вы ищете, улучшает ваше время до глубины, реализация многопоточности не так много для вас сделает (а в некоторых крайних случаях она может даже замедлить ее!). Вместо этого вам нужна более агрессивная обрезка дерева поиска и более эффективная реализация (например, отсутствие выделения памяти, чтобы никогда не запускался сборщик мусора и т. д.).

большое спасибо! Мне было трудно понять логику этого. Я рассмотрю Lazy SMP.

mrinin 30.03.2022 18:26

Другие вопросы по теме