score:2
The best solution is to change the Database access so that multiple objects are fetched within a single Future
. Even if there is a limit on the number of objects that can be fetched, it is still going to drastically reduce the overheads.
score:3
A neat trick to avoid context switching when using Scala Future
s consists in using parasitic
as an ExecutionContext
, which "steals execution time from other threads by having its Runnables run on the Thread which calls execute and then yielding back control to the caller after all its Runnables have been executed". parasitic
is available since Scala 2.13 but you can easily understand it and port it to pre-2.13 projects by looking at its code (here for version 2.13.1). A naive but working implementation for pre-2.13 projects would simply run the Runnable
s without taking care of dispatching them on a thread, which does the trick, as in the following snippet:
object parasitic212 extends ExecutionContext {
override def execute(runnable: Runnable): Unit =
runnable.run()
// reporting failures is left as an exercise for the reader
override def reportFailure(cause: Throwable): Unit = ???
}
The parasitic
implementation is of course more nuanced. For more insight into the reasoning and some caveats about its usage I would suggest you refer to the PR the introduced parasitic
as a publicly available API (it was already implemented but reserved for internal use).
Quoting the original PR description:
A synchronous, trampolining, ExecutionContext has been used for a long time within the Future implementation to run controlled logic as cheaply as possible.
I believe that there is a significant number of use-cases where it makes sense, for efficiency, to execute logic synchronously in a safe(-ish) way without having users to implement the logic for that ExecutionContext themselves—it is tricky to implement to say the least.
It is important to remember that ExecutionContext should be supplied via an implicit parameter, so that the caller can decide where logic should be executed. The use of ExecutionContext.parasitic means that logic may end up running on Threads/Pools that were not designed or intended to run specified logic. For instance, you may end up running CPU-bound logic on an IO-designed pool or vice versa. So use of parasitic is only advisable when it really makes sense. There is also a real risk of hitting StackOverflowErrors for certain patterns of nested invocations where a deep call chain ends up in the parasitic executor, leading to even more stack usage in the subsequent execution. Currently the parasitic ExecutionContext will allow a nested sequence of invocations at max 16, this may be changed in the future if it is discovered to cause problems.
As suggested in the official documentation for parasitic
, you're advised to only use this when the executed code quickly returns control to the caller. Here is the documentation quoted for version 2.13.1:
WARNING: Only ever execute logic which will quickly return control to the caller.
This ExecutionContext steals execution time from other threads by having its Runnables run on the Thread which calls execute and then yielding back control to the caller after all its Runnables have been executed. Nested invocations of execute will be trampolined to prevent uncontrolled stack space growth.
When using parasitic with abstractions such as Future it will in many cases be non-deterministic as to which Thread will be executing the logic, as it depends on when/if that Future is completed.
Do not call any blocking code in the Runnables submitted to this ExecutionContext as it will prevent progress by other enqueued Runnables and the calling Thread.
Symptoms of misuse of this ExecutionContext include, but are not limited to, deadlocks and severe performance problems.
Any NonFatal or InterruptedExceptions will be reported to the defaultReporter.
Source: stackoverflow.com
Related Query
- How to reduce context switches when traversing a Seq of Scala futures
- How to convert Seq to RDD when working with spark streaming context
- debugging scala futures - how to determine the future's execution context
- scala futures - keeping track of request context when threadId is irrelevant
- scala - how to flatten nested optional when using for loop with futures
- Chain Scala Futures when processing a Seq of objects?
- How to update a mongo record using Rogue with MongoCaseClassField when case class contains a scala Enumeration
- how to do sequential execution of Futures in scala
- How to flatten a List of Futures in Scala
- How To: debug Scala code when outside of an IDE
- How to reduce Scala (/ Java) startup overhead?
- How to resolve a list of futures in Scala
- how to keep return value when logging in scala
- How can I avoid mutable variables in Scala when using ZipInputStreams and ZipOutpuStreams?
- How does Scala maintains the values of variable when the closure was defined?
- When using Scala futures, will chained callbacks with the same execution context be optimised into synchronous calls?
- How do I alias the scala setter method 'myvar_$eq(myval)' to something more pleasing when in java?
- Why and how is Scala treating a tuple specially when calling a one arg function?
- How to properly access dbutils in Scala when using Databricks Connect
- How can I fix missing conf files when using shadowJar and Scala dependencies?
- How to set different scalacOptions per Scala version when cross-compiling using Build.scala?
- How to pass Scala Seq to a Java varargs
- How to refer to protected inner class in Scala when inheriting from Java (with byte code only)
- re-run with -feature for details, How to see scala feature warnings when building with gradle?
- How do you change lifted types back to Scala types when using Slick lifted embedding?
- Scala - how to explicitly choose which overloaded method to use when one arg must be null?
- How do I resolve "WILL_NOT_PERFORM" MS AD reply when trying to change password in scala w/ the unboundid LDAP SDK?
- How are Scala Futures chained together with flatMap?
- How does Scala use explicit types when resolving implicits?
- How to include javadoc of scala code when distributing library Jars?
More Query from same tag
- sbt key gets automatically capitalized after migration to sbt 1
- Spark 1.6: How do convert an RDD generated from a Scala jar to a pyspark RDD?
- Scala import packageName.ClassName VS import package._ overhead?
- "value >> is not a member of" compilation error
- Programmatically extract columns from Struct column as individual columns
- Rod Cutting in Functional Programming languages
- Play FrameWork / scala - return a streamed response from an Array[Byte]
- Reading excel file using apache poi in scala
- Flink Custom Partition Function
- Scala Action Map Implementation Issue (follow up)
- How to parse jsonfile with spark
- Play Framework Scala Template
- implicit extension methods on type refinements
- Improve performance of slow running spark streaming process that uses micro-batching
- Directing the body elsewhere Play 2.5
- Get last element of list in Spark Dataframe column
- Unpacking Future[Option[MyType]] in Scala
- Type mismatch issue
- How to read ASCII file with variable delimiters?
- fail to simulate play api Request
- Make scala.Long Comparable
- Scala Option type not inferred as expected
- Scala to Pyspark
- wrapping an asynchronous process in an akka actor
- How to mimic constructor arguments in a scala trait?
- I saved pdf file to AWS S3, but can’t download it from Chrome/Safari with https(ERR_HTTP2_PROTOCOL_ERROR)
- Spark - Change value of records which belong to the long tail in a Dataset
- Convert Resulting Rdd into HashMap
- Assigning each value as next item in Array in Scala
- Defining a generic to be a case class