Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala's blocking context doesn't seem to do well with mixed blocking / non-blocking jobs. Why?

I'm trying to make sense of the blocking construct. While it's not entirely clear how it internally works, the general idea I got was that as long as I used Scala's global thread-pool, wrapping my code with a blocking context would make sure the thread-pool would create extra space for this job (as it's not CPU bound).

  (1 to 1000).foreach { i =>
    Future {
      println(i)
      Thread.sleep(100 * 1000)
    }
  }

will quickly show that only 8 jobs can simultaneously run, while

  (1 to 1000).foreach { i =>
    Future {
        blocking {
            println(i)
            Thread.sleep(100 * 1000)
        }
    }
  }

will show that now we have around 250 simultaneous jobs. Wow! What then caught me off-guard was that

  (1 to 1000).foreach { i =>
    Future {
      println(i)
      Thread.sleep(100 * 1000)
    }
  }

  ('a' to 'z').foreach { c =>
    Future {
        blocking {
            println(c)
            Thread.sleep(100 * 1000)
        }
    }
  }

will again only show 8 simultaneous jobs -- the blocking jobs won't get executed right away.

Why is this? What really are the internal mechanics of the blocking context?

like image 966
devoured elysium Avatar asked Mar 26 '19 20:03

devoured elysium


1 Answers

blocking only takes effect once you've entered the blocking context. Since you have 8 non-blocking futures running, it won't start any new futures, so they can't enter the blocking context. In other words, Scala doesn't "know" they're blocking until they start being executed.

You can think of the second snippet as working like this:

  1. The first future is created and started.
  2. The first future signals that it is blocking via a call to blocking, so the implementation makes room for more futures.
  3. Meanwhile, on the main thread, the second future is created and started.
  4. ...

Whereas your last snippet works like this:

  1. The first future is created and started. It does not signal that it is blocking.
  2. The second future does the same.
  3. ...
  4. The 9th future is created, but not started, as there are 8 non-blocking futures.
  5. ...
  6. The 1001st future (the first one in the second loop) is created, but not started, as there are 8 non-blocking futures. Since it is not started, it never has the chance to tell the implementation that it is blocking by calling blocking.
like image 87
Brian McCutchon Avatar answered Oct 10 '22 20:10

Brian McCutchon