Utilisation de Java 8.
J'ai une classe Logger qui appelle une API chaque fois qu'il a besoin de se connecter quelque chose. J'ai réalisé que si l'API est en quelque sorte mal configuré, ou l'API ne vient pas répondre, mon action journal prend un beaucoup awefull de temps.
Exemple de journalisation synchrone:
public void debug(String message) {
MDC.clear();
MDC.put(SOME_KEY, "SOME_VALUE");
super.debug(message);
MDC.clear();
}
Je suis en mesure d'identifier que le problème est ici parce que si je viens tout commentaire et l'enregistrement d'arrêt ou de faire quelque chose, tout se passe aussi vite qu'il devrait:
public void debug(String message) {
// MDC.clear();
// MDC.put(SOME_KEY, "SOME_VALUE");
// super.debug(message);
// MDC.clear();
}
Donc, je pensais en faire un appel asynchrone, puisque je ne me soucie pas s'il est connecté de manière synchrone:
public void debug(String message) {
CompletableFuture.runAsync(() -> {
MDC.clear();
MDC.put(SOME_KEY, "SOME_VALUE");
super.debug(message);
MDC.clear();
});
}
Mais cet appel asynchrone est tout aussi mauvais, la performance sage pour mon application principale, comme l'appel synchrone. Qu'est-ce que je rate ?
Votre problème est que vous ne fournissez pas un exécuteur testamentaire. Cela peut provoquer Java pour vous fournir moins que les discussions que vous avez actuellement en attente des appels de débogage, ce qui signifie que vous obtenez encore un peu de blocage. Sur mon processeur Intel Core i7-4790 avec 4 coeurs et hyperthreading sur Java 8, il me semble d'obtenir 7 fils de discussion en cours d'exécution en même temps (nombre de CPU logiques - 1 pour le thread principal). Vous pouvez résoudre ce problème en fournissant un nombre illimité de fils en utilisant un pool de threads en cache:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Test
{
public static void main(String[] args) throws InterruptedException
{
Executor ex = Executors.newCachedThreadPool();
for(int i=0;i<100;i++)
{
CompletableFuture.runAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
System.out.println("completed");
},ex);
}
TimeUnit.SECONDS.sleep(2);
}
}
Voir l'exemple ci - dessus, qui imprime « complété » 100 fois. Si vous supprimez le ex
paramètre, il imprimera beaucoup moins.
Cependant, la cause sous-jacente des appels de débogage lent peut encore être fixée, car cela pourrait remplir votre mémoire si elle est une tâche longue en cours d'exécution.
Voir aussi: ( https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html ):
Toutes les méthodes async sans argument explicite Exécuteur sont effectuées à l'aide du ForkJoinPool.commonPool () (à moins qu'il ne supporte pas un niveau de parallélisme d'au moins deux, auquel cas, est créé un nouveau thread pour exécuter chaque tâche). [...]