Last active
January 4, 2019 13:52
-
-
Save fabrizioc1/ee167b91beb1c81dc80b626ed24b5bcb to your computer and use it in GitHub Desktop.
Comparing different concurrency methods using Scala
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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