Let’s put the parallel collection to a practical use. In Chapter 3, Scala and Functional Style, we looked at concise code to fetch and process stock prices from Yahoo. Let’s revisit that code and make it run parallel.
For this example, we’ll use the following tickers:
val tickers = List("AAPL", "AMD", "CSCO", "GOOG", "HPQ", "INTC", "MSFT", "ORCL")
The code to fetch the price and construct it into a StockPrice object is repeated from that chapter here.
| case class StockPrice(ticker : String, price : Double) { |
| def print = println("Top stock is " + ticker + " at price $" + price) |
| } |
| def getPrice(ticker : String) = { |
| val url = s"http://download.finance.yahoo.com/d/quotes.csv?s=${ticker}&f=snbaopl1" |
| val data = io.Source.fromURL(url).mkString |
| val price = data.split(",")(4).toDouble |
| StockPrice(ticker, price) |
| } |
The helper functions we needed to check if the stock prices are less than $500 and to pick the higher-priced stock are shown next:
| def isNotOver500(stockPrice : StockPrice) = stockPrice.price < 500 |
| def pickHigherPriced(stockPrice1 : StockPrice, stockPrice2 : StockPrice) = |
| if(stockPrice1.price > stockPrice2.price) stockPrice1 else stockPrice2 |
Finally, here’s the sequential code to compose all these to produce the desired result. We’ll measure the time to execute this code.
| Time.code { () => |
| tickers map getPrice filter isNotOver500 reduce pickHigherPriced print |
| } |
| //Top stock is ORCL at price $30.01 |
| //Time taken: 17.777705 |
The code took around seventeen seconds to get the prices from Yahoo and determine the highest-priced stock not over $500.
Let’s make a small change to the code to turn this into parallel execution.
| Time.code { () => |
| tickers.par map getPrice filter isNotOver500 reduce pickHigherPriced print |
| } |
| //Top stock is ORCL at price $30.01 |
| //Time taken: 3.805312 |
We inserted the call to par and invoked the map on the resulting parallel collection. All the requests to Yahoo and the subsequent calls to isNotOver500 are done in parallel. The only sequential part is the reduce operation and the resulting calls to pickHigherPriced. The parallel version took only around three seconds to produce the same result.
The functional programming style combined with powerful libraries make concurrent programming not only easier but also fun.