Scala — Future мелкие тонкости

В образовательных целях я написал проект на Scala c использованием Play Framework’е. Это веб-приложение, с более-мене удобным интерфесом, которое позволяет запускать и управлять роботами для инстаграма. Подробнее тут…

Роботы должны работать параллельно для чего нужен удобный механизм. Такой механизм в Scala есть. Это акторы и Future.

Каждый робот запускается внутри актора и Future. И все работало прекрасно, до некоторого времени… Вскоре выяснилось, что приложение зависает после запуска очередного робота.

Методом различных ухищрений стало понятно, что приложение зависает на запуске восьмого робота.

Суть ошибки оказалось в том, что каждая Future выполняется в некотором контексте. Этот самый контекст определяет сколько одновременно Furute’s могут быть запущено. Стандартный глобальный контекст:

Подразумевает, что может быть запущено столько Future’s, сколько ядер на процессоре. В Java есть класс:

В этом классе определяются статические методы для создания соответсвующего экзекутора для контекста. Если порыться в коде, то можно обнаружить строчку, которая, вероятно, создает экзекутора по-умолчанию:

Видно, строчку, в которой есть «availableProcessors», что и определяет количество потоков.

Говоря проще в состоянии из-коробки можно запустить одновременно столько Future, сколько у вас ядер на процессоре. Остальные Future  будут ждать, пока первые восемь не завершат свою работу. Именно поэтому приложение зависало после создания восьмого робота.

А решение простое, заменить контекст со стандартным экзекутором, на контекст с экзекутором с явным указанием количества потоков, например 100:

Есть и более гибкие экзекуторы, которые создаются соответствующими статическими методами класса Executors.