Меня спрашивали, как я задаю affinity потокам в яве в бенчмарках. Начнем с того, что из чистой явы это сделать нельзя. Но если нельзя, а очень хочется — то таки можно. Долгое время я пользовался на скорую руку сварганенным методом, подсмотренным где-то на stackoverflow. Потом какое-то время участвовал в разработке библиотеки Java-Thread-Affinity, от Питера Лоурея. В принципе, она довольно неплоха, и я могу ее вполне рекомендовать.
Однако, на мой взгляд, она предлагает слишком высокоуровневый подход. Мне самому кажется более привлекательной идея сначала разработать достаточно универсальное низкоуровневое API — просто удобным образом оттранслировать в яву стандартную функциональность ОС. А уж потом на этом фундаменте экспериментировать с различными вариантами высокоуровневого API. Потому что мне видится, что высокоуровневых API может быть несколько вариантов, под разные задачи, а вот низкоуровневое определяется системными возможностями, и разнообразие здесь существенно меньше, и легче найти такой вариант, который будет подходить для всех. Так что еще какое-то время назад я озадачился разработкой low-level affinity API.
Текущий (по-правде говоря — довольно черновой) вариант можно посмотреть здесь.
- Как подключить?
- Через maven:
<repository> <id>java-affinity-binding.googlecode.com</id> <name>AB Repository for Maven</name> <url>http://java-affinity-binding.googlecode.com/svn/repo/</url> </repository> ... <dependency> <groupId>org.affinity</groupId> <artifactId>affinity</artifactId> <version>0.1.1-SNAPSHOT</version> </dependency>
- Как пользоваться?
- Стартовая точка — статическая фабрика
ThreadAffinityUtils
. Через интерфейсCPULayoutService
можно получить список доступных вычислительных блоков (CPU
), аThreadAffinityService
позволяет задать список ядер, на которых текущий поток может выполняться.final ThreadAffinityService affinityService = ThreadAffinityUtils.defaultAffinityService(); if( affinityService.isActuallyAvailable() ) { final CPULayoutService layout =ThreadAffinityUtils.defaultLayoutService(); final CPU cpu = layout.cpu( 0 ); affinityService.restrictCurrentThreadTo( cpu ); } else { System.out.println( "Affinity binding is not supported by current OS" ); }
- Как это работает?
- Да просто дергаем
sched_setaffinity
на POSIX-системах, иSetThreadAffinityMask
на Windows. Дергаем через JNA, это позволяет не связываться с JNI напрямую, и не возиться самим с поддержкой различных платформ и компиляцией бинарников под каждую (этот гемморой берут на себя авторы JNA, за что им большое человеческое спасибо, искренняя уважуха, лучи добра и дай бог жену хорошую) - Но ведь JNA медленнее JNI?
- Да, медленнее. Но мне кажется, здесь это не принципиально — часто перепривязывать потоки с ядра на ядро не очень хорошая идея, скорее всего эти операции вообще будут делаться всего несколько раз за все время жизни потока. Так что несколько дополнительных миллисекунд погоды не делают
- Где это работает?
- На Windows и Linux точно. По-идее, будет работать так же на любых POSIX системах, но есть свои нюансы. Например, на Mac OS не работает — несмотря на то, что
sched_setaffinity
там есть, но семантика у него иная, нам не подходящая. - Ограничения
- В текущей версии задавать привязку можно только для текущего потока (того, который вызывает
.restrictCurrentThreadTo()
). Для вмешательства в другой поток нужно узнать его native thread id, а как это сделать "снаружи" этого потока я пока не нашел.Thread.getId()
возвращает просто порядковый номер потока в JVM, он не имеет ничего общего с native tid. Конечно, узнать список tid-ов текущего процесса можно — но ведь надо как-то отобразить их на джавовские потоки... В общем, привязать, скажем, GC к какому-то ядру пока не получится, получится только те потоки, в код которых вы можете вставить соответствующие вызовы
Код использовался в бенчмарках, но еще ни разу не использовался в рабочих приложениях. Если что — похороны за ваш счет.
Еще одна JavaAffinity библиотека. Здорово.
ОтветитьУдалитьПо-поводу native thread ID лучшее, что я нашел, это идти по стопам jstack. Вот тут хорошее описание:
https://gist.github.com/843622
Вот это "еще одна" меня самого смущало. Куча людей делают свои костыли, но такого, чтобы взять и пользоваться всем -- нет. Жалко
ОтветитьУдалитьСсылка очень полезная, спасибо. Я не нашел такой информации.