Explorar o código

Use `Dispatchers.Unconfined` in "vertx-web-kotlin-coroutines" to reduce overhead and improve performance (#7912)

* Add the `Dispatchers.Unconfined` argument to Coroutine `launch`s in `Route.handler`s to reduce the context switching overhead

Plaintext performance is almost tripled as tested on my machine.

* Add the "Unconfined" suffix to function names to better reflect their implementations
Shreck Ye %!s(int64=2) %!d(string=hai) anos
pai
achega
3f5bf976ce

+ 11 - 10
frameworks/Kotlin/vertx-web-kotlin-coroutines/src/main/kotlin/io/vertx/benchmark/App.kt

@@ -19,6 +19,7 @@ import io.vertx.kotlin.pgclient.pgConnectOptionsOf
 import io.vertx.kotlin.sqlclient.poolOptionsOf
 import io.vertx.pgclient.PgPool
 import io.vertx.sqlclient.Tuple
+import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.async
 import kotlinx.coroutines.awaitAll
 import kotlinx.coroutines.launch
@@ -41,8 +42,8 @@ class App : CoroutineVerticle() {
         private const val SELECT_FORTUNE = "SELECT id, message from FORTUNE"
     }
 
-    inline fun Route.coroutineHandler(crossinline requestHandler: suspend (RoutingContext) -> Unit): Route =
-        handler { ctx -> launch { requestHandler(ctx) } }
+    inline fun Route.coroutineHandlerUnconfined(crossinline requestHandler: suspend (RoutingContext) -> Unit): Route =
+        handler { ctx -> launch(Dispatchers.Unconfined) { requestHandler(ctx) } }
 
     inline fun RoutingContext.checkedRun(block: () -> Unit): Unit =
         try {
@@ -51,8 +52,8 @@ class App : CoroutineVerticle() {
             fail(t)
         }
 
-    inline fun Route.checkedCoroutineHandler(crossinline requestHandler: suspend (RoutingContext) -> Unit): Route =
-        coroutineHandler { ctx -> ctx.checkedRun { requestHandler(ctx) } }
+    inline fun Route.checkedCoroutineHandlerUnconfined(crossinline requestHandler: suspend (RoutingContext) -> Unit): Route =
+        coroutineHandlerUnconfined { ctx -> ctx.checkedRun { requestHandler(ctx) } }
 
     /**
      * PgClient implementation
@@ -228,7 +229,7 @@ class App : CoroutineVerticle() {
          * This test exercises the framework fundamentals including keep-alive support, request routing, request header
          * parsing, object instantiation, JSON serialization, response header generation, and request count throughput.
          */
-        app.get("/json").checkedCoroutineHandler { ctx ->
+        app.get("/json").checkedCoroutineHandlerUnconfined { ctx ->
             ctx.response()
                 .putHeader(HttpHeaders.SERVER, SERVER)
                 .putHeader(HttpHeaders.DATE, date)
@@ -241,27 +242,27 @@ class App : CoroutineVerticle() {
          * This test exercises the framework's object-relational mapper (ORM), random number generator, database driver,
          * and database connection pool.
          */
-        app.get("/db").checkedCoroutineHandler { ctx -> pgClientBenchmark.dbHandler(ctx) }
+        app.get("/db").checkedCoroutineHandlerUnconfined { ctx -> pgClientBenchmark.dbHandler(ctx) }
 
         /*
          * This test is a variation of Test #2 and also uses the World table. Multiple rows are fetched to more dramatically
          * punish the database driver and connection pool. At the highest queries-per-request tested (20), this test
          * demonstrates all frameworks' convergence toward zero requests-per-second as database activity increases.
          */
-        app.get("/queries").checkedCoroutineHandler { ctx -> pgClientBenchmark.queriesHandler(ctx) }
+        app.get("/queries").checkedCoroutineHandlerUnconfined { ctx -> pgClientBenchmark.queriesHandler(ctx) }
 
         /*
          * This test exercises the ORM, database connectivity, dynamic-size collections, sorting, server-side templates,
          * XSS countermeasures, and character encoding.
          */
-        app.get("/fortunes").checkedCoroutineHandler { ctx -> pgClientBenchmark.fortunesHandler(ctx) }
+        app.get("/fortunes").checkedCoroutineHandlerUnconfined { ctx -> pgClientBenchmark.fortunesHandler(ctx) }
 
         /*
          * This test is a variation of Test #3 that exercises the ORM's persistence of objects and the database driver's
          * performance at running UPDATE statements or similar. The spirit of this test is to exercise a variable number of
          * read-then-write style database operations.
          */
-        app.route("/update").checkedCoroutineHandler { ctx -> pgClientBenchmark.updateHandler(ctx) }
+        app.route("/update").checkedCoroutineHandlerUnconfined { ctx -> pgClientBenchmark.updateHandler(ctx) }
 
         /*
          * This test is an exercise of the request-routing fundamentals only, designed to demonstrate the capacity of
@@ -269,7 +270,7 @@ class App : CoroutineVerticle() {
          * still small, meaning good performance is still necessary in order to saturate the gigabit Ethernet of the test
          * environment.
          */
-        app.get("/plaintext").checkedCoroutineHandler { ctx ->
+        app.get("/plaintext").checkedCoroutineHandlerUnconfined { ctx ->
             ctx.response()
                 .putHeader(HttpHeaders.SERVER, SERVER)
                 .putHeader(HttpHeaders.DATE, date)