Статьи

Параллелизм и фоновые задачи в Grails

Могут ли веб-приложения получить выгоду от параллельного программирования? Должны ли веб-разработчики знать, как заставить несколько потоков вести себя и сотрудничать безопасно?
Если вы когда-либо обменивались данными по параллельным HTTP-запросам, совмещенным вызовам AJAX или просто нуждались в сокращении задержки запросов путем распараллеливания работы с большими кусками данных базы данных, высоки шансы, что ваш ответ на оба вопроса будет большим ДА . Параллельное программирование определенно становится актуальным для веб-приложений.

Параллельный Грааль

Теперь представьте, что вы работаете с приложением Grails и у вас есть набор дорогих вычислений, которые вы хотите выполнять асинхронно в фоновом режиме. Или, возможно, последовательная обработка коллекции изображений, загруженных пользователем, занимает слишком много времени, и у вас появилась идея использовать многоядерные микросхемы на ваших серверах, чтобы сократить время ожидания путем распараллеливания задания. Или же нужно обращаться к нескольким веб-службам в рамках обработки запросов, и вы чувствуете, что параллельное выполнение не может повредить. Или, ну, вы называете это. Список может продолжаться довольно долго.

Grails славится тем, что предоставляет программистам множество вариантов во всех важных областях, таких как безопасность, постоянство или презентация. Когда дело доходит до параллелизма, есть также несколько вариантов для выбора.

Без лишней работы просто используйте хорошо известные классы параллелизма Java 5. Или посмотрите предлагаемую библиотеку JSR-166y, в которой вы найдете удобные абстракции для Fork / Join и Parallel Array . Вы могли бы также рассмотреть плагин Grails для фоновой нити или использовать полиглотную природу Grails и выполнять параллельные действия на других языках, таких как Clojure.

Придерживаться Groovy

Но подождите, разве нет чистого решения Groovy? Может ли GPars , библиотека для параллелизма, основанная на Groovy и Groovy, помочь вам в Grails?

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

    dependencies {
        compile 'org.codehaus.gpars:gpars:0.11'
    }

Это вряд ли может быть проще.

Рассчитайте это в задней комнате

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

Closure myExpensiveCalculation = {...} 

withPool {
Future result = myExpensiveCalculation.callAsync()
}

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

Каждый получает задание

Часто вы можете столкнуться с ситуациями, когда вам нужно обработать набор элементов (строки данных, файлы, изображения, объекты, сервисы и т. Д.). Выполнение этого одновременно — это просто добавление Parallel к обычным именам методов коллекции Groovy.

def favoriteQuote = [lufthansa, ba, airfrance, delta]
.collectParallel{it.askForQuote myTrip}
.findAllParallel{it.serveVeganFood()}
.minParallel{it.price}

Не трогай мою корзину

Что делать, если вам нужны некоторые данные в памяти для совместного использования по запросам нескольких пользователей? Кеш может быть хорошим примером. Вы должны обрабатывать потенциально одновременные запросы, поступающие и попадающие в ваши данные, обеспечивать правильное распространение обновлений между потоками и не допускать повреждения данных в процессе работы. Точно так же нужно соблюдать осторожность, когда вы обмениваетесь данными между потенциально одновременными запросами одного пользователя (AJAX кто-нибудь?).

Обертывание части данных в агенте прекрасно решит проблемы во многих возможных сценариях.

def bookToBuy = Book.findBookByName('Griffon in Action')

def cartAgent = session['cart']

cartAgent << {Cart cart ->
if (!cart.contains bookToBuy) {
cart.add bookToBuy
}
}

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

Актеры, поток данных, форк / соединение и многое другое

Теперь вы можете пройти 3-х минутный Groovy Fast Track, чтобы лучше понять GPars. Параллелизм очень затягивает, когда выполняется на более высоком уровне абстракции. Как только вы начнете, вы захотите больше. Продолжайте приходить к руководству пользователя GPars для ваших обычных доз. Узнайте об актерах , ознакомьтесь с потоком данных и поэкспериментируйте с Fork / Join .

И больше всего, наслаждайтесь одновременностью в Grails!