Как насчет эволюционного алгоритма.
Начните с догадки. 1 поток на ядро ЦП выглядит неплохо, но зависит от поставленной задачи.
Измерение среднего времени для каждой задачи в поколении. Сравните это со временем предыдущего поколения. (Предположим, эффективно бесконечное время и 0 потоков для поколения 0).
Если для последних задач генерации было в среднем лучшее время, чем предыдущее, продолжайте изменять количество потоков в том же направлении, что и на предыдущем шаге (поэтому, если в последнем поколении было больше потоков, чем в предыдущем, добавьте поток для нового поколения, но если у него было меньше, то используйте одно меньше (очевидно, с нижним пределом в 1 поток).
Если самые последние задачи генерации занимали в среднем больше времени, чем предыдущее, то измените количество потоков в противоположном направлении (поэтому, если увеличение количества потоков привело к худшему времени, в следующий раз используйте меньшее количество потоков) .
Пока оптимальное количество потоков не слишком близко к 1, вы, вероятно, будете колебаться между 3 значениями, которые все достаточно близки к оптимальным. Вы можете явно определить этот случай и зафиксировать центральное значение, если вам приходится иметь дело с большим числом поколений.