Revisiting an Earlier Example

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.

Footnotes

[19]

http://akka.io