Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

document that ECs must be async to be general purpose #8377

Closed
scabug opened this issue Mar 7, 2014 · 8 comments
Closed

document that ECs must be async to be general purpose #8377

scabug opened this issue Mar 7, 2014 · 8 comments
Assignees
Labels
Milestone

Comments

@scabug
Copy link

scabug commented Mar 7, 2014

The following example uses an ExecutionContext with direct, synchronous execution.

  def futureTest: Int = {
    import scala.concurrent.duration._
    implicit val immediateContext = new scala.concurrent.ExecutionContext {
      override def execute(runnable: Runnable) { runnable.run() }
      override def reportFailure(t: Throwable) { t.printStackTrace() }
    }
    val normal = scala.concurrent.ExecutionContext.fromExecutor(java.util.concurrent.Executors.newCachedThreadPool())
    val initial = scala.concurrent.Future({ Thread.sleep(1000); 1 })(normal)
    val res = initial.flatMap(x1 => scala.concurrent.Future.successful(2)).flatMap(x2 => {
      val res2 = scala.concurrent.Future.successful(3).flatMap(x3 => scala.concurrent.Future.successful(4))
      scala.concurrent.Await.ready(res2, 300 seconds)   // this throws the IllegalArgumentException
    })
    scala.concurrent.Await.result(res, 300 seconds)
  }
  futureTest

It fails with

java.lang.IllegalArgumentException: requirement failed
at scala.Predef$.require(Predef.scala:221)
at scala.concurrent.Future$InternalCallbackExecutor$Batch.run(Future.scala:628)
at scala.concurrent.Future$InternalCallbackExecutor$.scala$concurrent$Future$InternalCallbackExecutor$$unbatchedExecute(Future.scala:691)
at scala.concurrent.Future$InternalCallbackExecutor$Batch.blockOn(Future.scala:669)
at scala.concurrent.Await$.ready(package.scala:86)
at $anonfun$3.apply(:17)
at $anonfun$3.apply(:15)
at scala.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:251)
at scala.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:249)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
at $anon$1.execute(:10)
at scala.concurrent.impl.CallbackRunnable.executeWithValue(Promise.scala:40)
at scala.concurrent.impl.Promise$DefaultPromise.tryComplete(Promise.scala:248)
at scala.concurrent.Promise$class.complete(Promise.scala:55)
at scala.concurrent.impl.Promise$DefaultPromise.complete(Promise.scala:153)
at scala.concurrent.Future$$anonfun$flatMap$1$$anonfun$apply$3.apply(Future.scala:254)
at scala.concurrent.Future$$anonfun$flatMap$1$$anonfun$apply$3.apply(Future.scala:254)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
at scala.concurrent.Future$InternalCallbackExecutor$Batch$$anonfun$run$1.processBatch$1(Future.scala:640)
at scala.concurrent.Future$InternalCallbackExecutor$Batch$$anonfun$run$1.apply$mcV$sp(Future.scala:655)
at scala.concurrent.Future$InternalCallbackExecutor$Batch$$anonfun$run$1.apply(Future.scala:632)
at scala.concurrent.Future$InternalCallbackExecutor$Batch$$anonfun$run$1.apply(Future.scala:632)
at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:72)
at scala.concurrent.Future$InternalCallbackExecutor$Batch.run(Future.scala:631)
at scala.concurrent.Future$InternalCallbackExecutor$.scala$concurrent$Future$InternalCallbackExecutor$$unbatchedExecute(Future.scala:691)
at scala.concurrent.Future$InternalCallbackExecutor$.execute(Future.scala:682)
at scala.concurrent.impl.CallbackRunnable.executeWithValue(Promise.scala:40)
at scala.concurrent.impl.Promise$KeptPromise.onComplete(Promise.scala:333)
at scala.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:254)
at scala.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:249)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
at $anon$1.execute(:10)
at scala.concurrent.impl.CallbackRunnable.executeWithValue(Promise.scala:40)
at scala.concurrent.impl.Promise$DefaultPromise.tryComplete(Promise.scala:248)
at scala.concurrent.Promise$class.complete(Promise.scala:55)
at scala.concurrent.impl.Promise$DefaultPromise.complete(Promise.scala:153)
at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:23)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)

The stack trace is from 2.10.3, but it also fails in 2.11.0-RC1. The stack strace looks very similar to that of #8069.
Batch#blockOn looks suspicious, setting _tasksLocal to Nil and then calling run which requires it to be null. Also the "WARNING" comment from BatchingExecutor seems to apply to InternalCallbackExecutor.

@scabug
Copy link
Author

scabug commented Mar 7, 2014

Imported From: https://issues.scala-lang.org/browse/SI-8377?orig=1
Reporter: Niklas Nebel (niklasn)
Affected Versions: 2.10.3, 2.11.0-RC1

@scabug
Copy link
Author

scabug commented Mar 7, 2014

@retronym said:
Recent mailing list thread discussing why an immediate (ie current thread) execution context can be problematic: https://groups.google.com/forum/#!msg/scala-user/lVFde4UyBvc/lml-BkIGQuYJ

@scabug
Copy link
Author

scabug commented Mar 7, 2014

@retronym said:
/cc @viktorklang

@scabug
Copy link
Author

scabug commented Mar 7, 2014

Viktor Klang (viktorklang) said:
implicit val immediateContext = new scala.concurrent.ExecutionContext {
override def execute(runnable: Runnable) { runnable.run() }
override def reportFailure(t: Throwable) { t.printStackTrace() }
}

This is not a valid execution context. We will update the documentation to explain that ECs must be async to be general purpose—i.e. you can only use the construct above to execute your own code.

@scabug
Copy link
Author

scabug commented Mar 7, 2014

Viktor Klang (viktorklang) said:
See this discussion for more background: https://groups.google.com/forum/#!searchin/scala-user/Future$20$26$20ExecutionContext/scala-user/LKiVD2PGvew/XDT-UZrAjJcJ

@scabug
Copy link
Author

scabug commented Mar 10, 2014

Viktor Klang (viktorklang) said:
scala/scala#3613

@scabug scabug closed this as completed Mar 10, 2014
@scabug
Copy link
Author

scabug commented Mar 21, 2014

@nilskp said:
Any chance this can make it into 2.10.4?

@scabug
Copy link
Author

scabug commented Mar 21, 2014

@retronym said:
2.10.4 final has already been cut. We'd accept a pull request that cherry-picks the doc fix to the 2.10.x branch. That would be included in 2.10.5.

@scabug scabug added the library label Apr 7, 2017
@scabug scabug added this to the 2.11.0-RC3 milestone Apr 7, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants