@@ -440,3 +440,114 @@ and register that when building the HttpClientContext.
440440All requests using the HttpClientContext will automatically get
441441an ` Authorization ` header with ` Bearer ` token added. The token will be
442442obtained for initial request and then renewed when the token has expired.
443+
444+
445+ # 10K requests - Loom vs Async
446+
447+ The following is a very quick and rough comparison of running 10,000 requests
448+ using ` Async ` vs ` Loom ` .
449+
450+ To run this test myself I use [ Jex] ( https://github.com/avaje/avaje-jex ) as the
451+ server (Jetty based) and have it running using Loom.
452+
453+ The Loom blocking request (make 10K of these)
454+
455+ ``` java
456+ HttpResponse<String > hres = httpClient. request()
457+ .path(" s200" )
458+ . GET ()
459+ .asString();
460+ ```
461+ The equivalent async request (make 10K of these joining the CompletableFuture's).
462+
463+ ``` java
464+ CompletableFuture<HttpResponse<String > > future = httpClient. request()
465+ .path(" s200" )
466+ . GET ()
467+ .async()
468+ .asString()
469+ .whenComplete((hres, throwable) - > {
470+ ...
471+ });
472+ ```
473+
474+
475+ ### 10K requests using Async and reactive streams
476+
477+ Use ` .async() ` to execute the requests which internally is using JDK
478+ HttpClient's reactive streams. The ` whenComplete() ` callback is invoked
479+ when the response is ready. Collect all the resulting CompletableFuture
480+ and wait for them all to complete.
481+
482+ ``` java
483+
484+ // Collect all the CompletableFuture's
485+ List<CompletableFuture<HttpResponse<String > > > all = new ArrayList<> ();
486+
487+ long start = System . currentTimeMillis();
488+ for (int i = 0 ; i < 10_000 ; i++ ) {
489+ all. add(httpClient. request(). path(" s200" )
490+ . GET ()
491+ .async(). asString()
492+ .whenComplete((hres, throwable) - > {
493+ output(hres);
494+ }));
495+ }
496+
497+ // wait for them all to complete ..
498+ CompletableFuture . allOf(all. toArray(new CompletableFuture [0 ]))
499+ .join();
500+
501+ long exeMs = System . currentTimeMillis() - start;
502+ System . out. println(" Complete ... exeMillis:" + exeMs);
503+ ```
504+ Runs is approx 5 to 5.5 seconds on my environment (without sout).
505+
506+ ### 10K requests using Loom
507+
508+ With Loom Java 17 EA Release we can use ` Executors.newVirtualThreadExecutor() `
509+ to return an ExecutorService that uses Loom Virtual Threads. These
510+ are backed by "Carrier threads" (via ForkedJoinPool).
511+
512+ ``` java
513+
514+ long start = System . currentTimeMillis();
515+
516+ // Use Loom's Executors.newVirtualThreadExecutor()
517+
518+ try (ExecutorService executorService = Executors . newVirtualThreadExecutor()) {
519+ for (int i = 0 ; i < 10_000 ; i++ ) {
520+ executorService. submit(this :: task);
521+ }
522+ }
523+
524+ long exeMs = System . currentTimeMillis() - start;
525+ System . out. println(" Complete ... exeMillis:" + exeMs);
526+ ```
527+ ``` java
528+ private void task() {
529+ HttpResponse<String > hres = performGet();
530+ System . out. println(" status:" + hres. statusCode() + " length:" + hres. body(). length());
531+ }
532+
533+ private HttpResponse<String > performGet() {
534+ return httpClient. request()
535+ .path(" s200" )
536+ . GET ()
537+ .asString();
538+ }
539+ ```
540+
541+ Running in approx 4.5 to 5 seconds on my environment (without sout).
542+
543+ It looks like Loom and Async run in pretty much the same time although
544+ it could be that Loom is just a slight touch faster. I need to do more
545+ investigation.
546+
547+ Build used is: ` 17 EA 2021-09-14 / (build 17-loom+7-342) ` .
548+
549+ ```
550+ openjdk version "17-loom" 2021-09-14
551+ OpenJDK Runtime Environment (build 17-loom+7-342)
552+ OpenJDK 64-Bit Server VM (build 17-loom+7-342, mixed mode, sharing)
553+ ```
0 commit comments