Ich versuche, die Vorteile von Async in Java zu verstehen.Java - Async - Thread-Pool
Szenario 1: I eine Federverschluß-Webanwendung tomcat bereitgestellt habe, mit tomcat min und max Fäden beide auf 200.
@Service
public class MyService{
public String execute(){
try {
//simulate blocking
Thread.sleep(3000);
} catch (InterruptedException e) {}
return "OK";
}
}
@RestController
public class MyController {
@Autowired
private MyService service;
@RequestMapping("/test")
public String test(){
return service.execute();
}
}
Szenario 2: Ich habe eine Federverschluß-Webanwendung tomcat entfalteten die Gesamtzahl der Threads mit tomcat min und max Fäden beide auf 100
@Service
public class MyService{
public String execute(){
try {
//simulate blocking
Thread.sleep(3000);
} catch (InterruptedException e) {}
return "OK";
}
}
@RestController
public class MyController {
@Autowired
private MyService service;
private ExecutorService executorService = Executors.newFixedThreadPool(100);
@RequestMapping("/test")
public DeferredResult<String> test(){
DeferredResult<String> deferredResult = new DeferredResult<>();
CompletableFuture.supplyAsync(service::execute, executorService).
whenCompleteAsync((result, throwable) -> deferredResult.setResult(result));
return deferredResult;
}
}
In jeder Szenarien ist 200.
Aber ich sehe nicht, wie scen Ario 2 wird besser funktionieren:
In Szenario 1, wenn 400 Anfragen zur gleichen Zeit eingehen, werden die ersten 200 von den 200 HTTP-Threads bedient und die nächsten 200 müssen 3 Sekunden warten (plus ein bisschen) bis einer der Threads wieder verfügbar wird.
So war der Durchsatz 400 Anfragen pro 6 Sekunden = 66,6 Anfragen pro Sekunde.
durchschnittliche Antwortzeit war (200 * 200 * 3 + 6)/(400) = 4,5 Sekunden
In Szenario 2 wenn 400 Anfragen zur gleichen Zeit kommen. Die ersten 100 werden sofort von den 100 http-Threads bedient, wobei jeder dieser Threads den Dienst aufruft, nicht auf das Ergebnis wartet und dann sofort wieder aufnimmt und verfügbar wird, um die nächsten 100 Anfragen zu bedienen. Aber jetzt für die zweiten 100 Anfragen, wenn jeder der http-Threads den Dienst aufruft, wartet dieser Dienst momentan 3 Sekunden (minus ein bisschen), um die Verarbeitung der ersten 100 Threads zu beenden. Die nächsten 100 werden in die Warteschlange gestellt (im Threadpool des Executorservice). So haben wir in kürzester Zeit alle 400 Anfragen bearbeitet, aber 100 werden im Service bearbeitet (3 Sekunden warten), während 300 im Executor Service Thread Pool in der Warteschlange stehen. 3 Sekunden später werden die ersten 100 fertiggestellt, die nächsten 100 aus der Warteschlange genommen und verarbeitet und so weiter.
also der Durchsatz beträgt 400 Anfragen in 12 Sekunden = 33,3 Anfragen pro Sekunde
durchschnittliche Antwortzeit war (100 * 3 + 100 * 6 + 100 * 9 + 100 * 12)/(400) = 7,5 Sekunden
Nun könnte jemand argumentieren: "Ich kann Szenario 2 verbessern, indem ich die Anzahl der Threads im Executor-Service-Thread-Pool erhöhe", auf die ich antworten könnte: "Gut, dann kann ich die Anzahl der Threads in Tomcat erhöhen Pool in Szenario 1 um den gleichen Betrag '
Danke für die Antwort. Wenn der Dienst jedoch auch async ist und sofort zurückkehrt, welcher Thread auf die Antwort wartet, die die ausführbare Zukunft abschließt –
Der Aufrufer der API wartet immer noch auf die Antwort 'OK'. Ein Thread muss diese Antwort zurückgeben, auch wenn es sich nicht um einen Tomcat-HTTP-Thread handelt. –
@ jonathan.stiles - Wenn die Zeit für eine Zeitgeberaufgabe verstrichen ist, wird die Aufgabe einem inaktiven Thread im Threadpool zugewiesen, oder wenn kein inaktiver Thread vorhanden ist, wird sie einer Warteschlange zugewiesen, die beim nächsten Thread in der Warteschlange bedient wird Pool wird inaktiv. Dieser Thread aus dem Thread-Pool vervollständigt schließlich das DeferredResult und sendet die Antwort an den Client. In ordnungsgemäßem async werden alle Threads in dem Thread-Pool, der darauf wartet, geplant zu werden, entweder erledigt oder sind inaktiv. – antlersoft