Example Using Grails Promises
I was recently playing around with the Asynchronous Programming features in Grails using Promises, and wanted to share an example that went a little beyond a simple example. In case you are using an older version of Grails, the asynchronous features where added in Grails 2.3. While there are a lot of useful asynchronous features in Grails, for this article I'll only focus on using Promises. Promises are a common concept being introduced in many concurrency frameworks. They are similar to Java's java.util.concurrent.Future class, but like all things with Grails/Groovy, Grails has made them easier to use.
First, before showing you an example, go ahead and run grails console
under an existing grails project. If you don't have one, install grails (see GVM) and run grails create-app
. Using the grails console will allow you to quickly run these examples and experiment on your own.
Basic Example
import static grails.async.Promises.task import static grails.async.Promises.waitAll def task1 = task { println "task1 - starting" Thread.sleep(5000) println "task1 - ending" } def task2 = task { println "task2 - starting" Thread.sleep(1000) println "task2 - ending" } waitAll(task1, task2)This would output:
task1 - starting task2 - starting task2 - ending task1 - ending
More Complex Example
Let's say you wanted to list the states of 5 zip codes. Here is what that would look like if we did it synchronously:
["74172", "64840", "67202", "68508", "37201"].each { z -> println "getting state for zip code: $z" def response = new URL("http://zip.getziptastic.com/v2/US/$z").content.text def json = grails.converters.JSON.parse(response) println "zip code $z is in state $json.state" }And the output for that would look like:
getting state for zip code: 74172 zip code 74172 is in state Oklahoma getting state for zip code: 64840 zip code 64840 is in state Missouri getting state for zip code: 67202 zip code 67202 is in state Kansas getting state for zip code: 68508 zip code 68508 is in state Nebraska getting state for zip code: 37201 zip code 37201 is in state Tennessee
And here is what it would look like using Grails Promises to make it asynchronous:
import static grails.async.Promises.task import static grails.async.Promises.waitAll def tasks = ["74172", "64840", "67202", "68508", "37201"].collect { z -> task { println "getting state for zip code: $z" def response = new URL("http://zip.getziptastic.com/v2/US/$z").content.text def json = grails.converters.JSON.parse(response) println "zip code $z is in state $json.state" } } waitAll(tasks)
The asynchronous output would look like this:
getting state for zip code: 37201 getting state for zip code: 68508 getting state for zip code: 67202 getting state for zip code: 64840 getting state for zip code: 74172 zip code 74172 is in state Oklahoma zip code 37201 is in state Tennessee zip code 64840 is in state Missouri zip code 68508 is in state Nebraska zip code 67202 is in state Kansas
Each time you run the asynchronous version it will output a different order because the tasks are running asynchronously. The
waitAll()
method will block until all tasks complete.Thanks to jeremydanderson for helping me figure out how best to use the
collect
method.