Хватит ждать и начните многопоточность
Несмотря на то, что Julia — один из самых быстрых языков, иногда выполнение некоторых вещей может занять некоторое время. Если вы специалист по данным или аналитик, использующий Julia, возможно, вы хотите отправить вычисления на сервер, дождаться их завершения, а затем что-то сделать с результатами.
Но ждать скучно.
Когда вы заняты работой, полны идей и энтузиазма по созданию чего-то интересного, вам хочется продолжать стучать по клавиатуре, чтобы найти что-то еще.
Позвольте мне показать вам простую технику в Julia, как вы можете перенаправить вычисления в другой поток и продолжить свою работу.
Настройка вещей
Как я уже говорил, Джулия быстрая. Как современный язык, он также построен с учетом многопроцессорности. Таким образом, использовать эти дополнительные ядра на вашей машине легко, если вы знаете, как это сделать.
Прежде всего, мы должны убедиться, что запускаем экземпляр Julia с несколькими потоками:
julia -t 4
Это запустит Джулию, использующую 4 потока. Мы можем подтвердить это, запросив количество потоков:
julia> using Base.Threads julia> Threads.nthreads() 4
Делаем медленную функцию
Теперь, когда у нас есть больше потоков, пришло время увидеть эту магию в действии. Но нам нужно что-то, чтобы запустить какое-то время, чтобы это имело смысл. Я предполагаю, что если вы читаете эту статью, у вас уже есть что-то на уме, но поскольку я предпочитаю иметь полные примеры в своих статьях, я напишу здесь небольшую функцию, чтобы развлечь себя.
Эта «медленная» функция может быть вызовом для построения модели ML, выполнения некоторых SQL-подобных запросов к базе данных или извлечения некоторых данных из облачного хранилища. Используйте свое воображение и сойти с ума!
julia> function collatz(n, i=0) if n == 1 i elseif iseven(n) collatz(n / 2, i + 1) else collatz(3n + 1, i + 1) end end collatz (generic function with 2 methods) julia> collatz(989345275647) 1348 julia> averageSteps(n) = sum(i -> collatz(i) / n, 1:n) averageSteps (generic function with 1 method
Если вам интересно, о чем идет речь выше и почему я выбрал 989 345 275 647, то прочитайте эту страницу вики.
Получение немного магии
Поскольку в нашем пространстве имен есть Threads
, мы можем использовать макрос @spawn
для отправки вычислений в другой поток. Это означает, что мы немедленно вернем наш REPL и сможем продолжать работать, как раньше.
julia> res = @spawn averageSteps(1e7) Task (runnable) @0x000000015d061f90 julia> 2^5 + 12 44 julia> fetch(res) 155.2724831
Не обращайте внимания на отсутствие у меня воображения, я просто не мог придумать что-то более сложное после появления.
По сути, здесь происходит то, что @spawn
возвращает Task
. Его задача автоматически перенаправляется в свободный поток, который может работать над ней в фоновом режиме, позволяя тем временем писать больше кода и задавать больше вопросов. Когда вам понадобятся результаты, вы можете собрать результаты задач с помощью fetch
, которые будут ждать завершения Task
и возвращать результаты.
Доказательство того, что это работает
Один из способов показать, что это действительно работает, — показать некоторые тайминги.
Во-первых, мы запустим нашу функцию в текущем потоке и измерим время, которое она занимает. Затем мы создадим Task
и, наконец, создадим и сразу же дождемся результатов.
julia> @time averageSteps(1e7) 16.040698 seconds 155.2724831 julia> @time res = @spawn averageSteps(1e7) 0.009290 seconds (31.72 k allocations: 1.988 MiB) Task (runnable) @0x000000015d179f90 julia> @time fetch(@spawn averageSteps(1e7)) 16.358641 seconds (24.31 k allocations: 1.553 MiB, 0.06% compilation time) 155.2724831
Как видите, наша функция выполняется примерно за 16 секунд. Но если мы отправляем задачу, то мы немедленно возвращаем задачу. Это связано с некоторыми накладными расходами, как вы можете видеть в последней строке, поскольку это немного (0,3 с) медленнее, чем просто выполнение вычислений в основном потоке.
Спасибо за прочтение!
Надеюсь, этот небольшой трюк расскажет новичкам в Julia о потрясающих сверхспособностях, которые может дать им современный многопоточный язык. Если вам понравилось читать мой бред на эту тему, поставьте мне 👏 или 👏 👏.