GitHub user rikhmaier added a comment to the discussion: [Q/A][Java SDK
(Component)] For asynchronous calls, should I use asyncCall or virtual threads?
Neither option is universally “better”; they represent two different
programming models.
`RpcContext.asyncCall(...)` is appropriate when the surrounding code is already
asynchronous and you want to compose the result without occupying one
application thread per request:
```java
CompletableFuture<Result> future =
RpcContext.getServiceContext()
.asyncCall(() -> remoteService.query(req));
return future.thenApply(this::transform);
```
Ideally, keep the chain asynchronous instead of eventually calling `get()` on a
platform thread.
Virtual threads are useful when you prefer straightforward synchronous code. In
that case, the important part is that the complete request/task is already
running on a virtual thread. You can then call the synchronous Dubbo proxy
directly:
```java
Result result = remoteService.query(req);
return transform(result);
```
Wrapping one synchronous call in a newly created executor and immediately
calling `get()` usually adds another scheduling boundary without providing
useful concurrency. The caller still waits for the same RPC. A virtual-thread
executor becomes useful for fan-out, where several independent calls run
concurrently:
```java
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
Future<A> a = executor.submit(() -> serviceA.query(req));
Future<B> b = executor.submit(() -> serviceB.query(req));
return combine(a.get(), b.get());
}
```
Therefore:
* Existing asynchronous/reactive pipeline: use Dubbo's asynchronous API and
compose the `CompletableFuture`.
* Imperative thread-per-request application on JDK 21+: run the request on a
virtual thread and use the normal synchronous Dubbo call.
* Parallel fan-out from imperative code: virtual threads are a convenient
option.
* Do not wrap `asyncCall()` in another executor; Dubbo already performs the
network operation asynchronously.
* Virtual threads improve scalability/throughput for blocking code, not the
latency of an individual RPC.
Also be careful with `RpcContext`: it is request/thread context. If you submit
the call to another thread, set any required attachments inside that submitted
task or use the supported context-propagation mechanism; do not assume
arbitrary `ThreadLocal` state will follow it.
Finally, virtual threads should not be used as a downstream concurrency limit.
If the remote service must receive at most N concurrent calls, use a
`Semaphore`, bulkhead, or Dubbo-side concurrency controls. Creating cheap
virtual threads does not provide backpressure.
Oracle’s virtual-thread guidance makes the same distinction: synchronous
blocking code benefits from virtual threads, while an already non-blocking
`CompletableFuture` pipeline generally does not:
https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html
Dubbo 3.3 also documents Project Loom support:
https://dubbo.apache.org/en/blog/2024/09/11/apache-dubbo-3.3-released-triple-x-leads-a-new-era-of-microservices-communication/
GitHub link:
https://github.com/apache/dubbo/discussions/16379#discussioncomment-18604808
----
This is an automatically sent email for [email protected].
To unsubscribe, please send an email to:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]