Skip to content

Instantly share code, notes, and snippets.

@fabrizioc1
Last active January 4, 2019 13:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fabrizioc1/ee167b91beb1c81dc80b626ed24b5bcb to your computer and use it in GitHub Desktop.
Save fabrizioc1/ee167b91beb1c81dc80b626ed24b5bcb to your computer and use it in GitHub Desktop.
Comparing different concurrency methods using Scala
import requests._
import org.json4s._
import org.json4s.jackson.{JsonMethods => Json}
import org.json4s.JsonDSL.WithBigDecimal._
import scala.concurrent._
import scala.concurrent.duration._
// import ExecutionContext.Implicits.global
import java.lang.Runtime
import java.util.concurrent.{Executor, Executors}
object HackerNews {
implicit val formats = DefaultFormats
val API_URL = "https://hacker-news.firebaseio.com/v0"
case class Item(id: BigInt, title: String, url: Option[String])
def topStoryIds() = {
val url = s"${API_URL}/topstories.json"
val response = requests.get(url)
for (JInt(itemId) <- Json.parse(response.text)) yield itemId
}
def item(id: BigInt) = {
val url = s"${API_URL}/item/${id}.json"
val response = requests.get(url)
Json.parse(response.text).extract[Item]
}
}
def fetchStoriesWithElapsedTime(itemIds: Seq[BigInt], downloader: Seq[BigInt] => Seq[HackerNews.Item]) = {
val startTime = System.currentTimeMillis
val stories = downloader(itemIds)
val elapsedTime = System.currentTimeMillis - startTime
(stories, elapsedTime)
}
def fetchStoriesWithoutFutures(itemIds: Seq[BigInt]) {
itemIds.map(itemId => HackerNews.item(itemId))
}
def fetchStoriesWithFuturesV1(itemIds: Seq[BigInt]) = {
implicit val executor = ExecutionContext.global
val futures = itemIds.map { itemId => Future { HackerNews.item(itemId) } }
val stories = Future.sequence(futures)
Await.result(stories, Duration.Inf)
}
def fetchStoriesWithFuturesV2(itemIds: Seq[BigInt]) = {
val availableProcessors = Runtime.getRuntime.availableProcessors
val fixedThreadPoolExecutor = Executors.newFixedThreadPool(availableProcessors)
val customExecutionContext = ExecutionContext.fromExecutor(fixedThreadPoolExecutor)
try {
val futures = itemIds.map { itemId => Future { HackerNews.item(itemId) }(customExecutionContext) }
val stories = Future.sequence(futures)(implicitly, customExecutionContext)
Await.result(stories, Duration.Inf)
}
finally {
fixedThreadPoolExecutor.shutdownNow
}
}
def fetchStoriesWithParallelCollections(itemIds: Seq[BigInt]) = {
itemIds.par.map(itemId => HackerNews.item(itemId)).seq
}
val topStoryIds = HackerNews.topStoryIds()
val (stories0, elapsedTime) = fetchStoriesWithElapsedTime(topStoryIds, fetchStoriesWithoutFutures)
val (stories1, elapsedTimeWithFutures1) = fetchStoriesWithElapsedTime(topStoryIds, fetchStoriesWithFuturesV1)
val (stories2, elapsedTimeWithFutures2) = fetchStoriesWithElapsedTime(topStoryIds, fetchStoriesWithFuturesV2)
val (stories3, elapsedTimeWithParallelCollections) = fetchStoriesWithElapsedTime(topStoryIds, fetchStoriesWithParallelCollections)
val percentTimeSaved1 = 1.0 * (elapsedTime - elapsedTimeWithFutures1) / elapsedTime
val percentTimeSaved2 = 1.0 * (elapsedTime - elapsedTimeWithFutures2) / elapsedTime
val percentTimeSaved3 = 1.0 * (elapsedTime - elapsedTimeWithParallelCollections) / elapsedTime
println(s"Percent time saved #1: ${percentTimeSaved1}")
println(s"Percent time saved #2: ${percentTimeSaved2}")
println(s"Percent time saved #3: ${percentTimeSaved3}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment