Dans de nombreux services sur lesquels je travaille, il y a beaucoup de journalisation en cours. Les services sont des services WCF (principalement) qui utilisent la classe .NET EventLogger.
Je suis en train d'améliorer les performances de ces services et je dois penser que la journalisation asynchrone bénéficierait aux performances.
Je ne sais pas ce qui se passe lorsque plusieurs threads demandent à se connecter, et si cela crée un goulot d'étranglement, mais même si ce n'est pas le cas, je pense toujours que cela ne devrait pas interférer avec le processus en cours d'exécution.
Je pense que je devrais invoquer la même méthode de journal que j'appelle maintenant, mais le faire en utilisant un nouveau thread, tout en poursuivant le processus réel.
Quelques questions à ce sujet:
Est-ce que c'est bon?
Y a-t-il des inconvénients?
Faut-il le faire d'une manière différente?
Peut-être que c'est si rapide que ça ne vaut même pas la peine?
Réponses:
Un thread séparé pour le fonctionnement des E / S semble raisonnable.
Par exemple, il ne serait pas bon d'enregistrer les boutons sur lesquels l'utilisateur a appuyé dans le même thread d'interface utilisateur. Une telle interface utilisateur se bloque au hasard et a des performances perçues lentes .
La solution consiste à dissocier l'événement de son traitement.
Voici beaucoup d'informations sur le problème des producteurs-consommateurs et la file d'attente des événements du monde du développement de jeux
Il y a souvent un code comme
Cette approche conduira à un conflit de thread. Tous les threads de traitement se battront pour pouvoir obtenir le verrouillage et écrire dans le même fichier à la fois.
Certains peuvent essayer de supprimer les verrous.
Il n'est pas possible de prédire le résultat si 2 threads entreront en même temps dans la méthode.
Ainsi, les développeurs désactiveront finalement la journalisation ...
Est-il possible de réparer?
Oui.
Disons que nous avons une interface:
Au lieu d'attendre le verrouillage et d'effectuer une opération de blocage de fichier à chaque
ILogger
appel, nous ajouterons un nouveau LogMessage à la file d'attente des messages de ping et reviendrons à des choses plus importantes:Nous avons terminé avec ce simple enregistreur asynchrone .
L'étape suivante consiste à traiter les messages entrants.
Pour plus de simplicité, permet de démarrer un nouveau thread et d'attendre indéfiniment jusqu'à ce que l'application se termine ou que l' enregistreur asynchrone ajoute un nouveau message à la file d'attente en attente .
Je passe une chaîne d'auditeurs personnalisés. Vous voudrez peut-être simplement envoyer un cadre de journalisation des appels (
log4net
, etc ...)Voici le reste du code:
Point d'accès:
la source
Les facteurs clés à considérer sont votre besoin de fiabilité dans les fichiers journaux et le besoin de performances. Reportez-vous aux inconvénients. Je pense que c'est une excellente stratégie pour les situations de haute performance.
Est-ce que ça va - oui
Existe-t-il des inconvénients - oui - selon la criticité de votre journalisation et de votre implémentation, l'un des événements suivants peut se produire - journaux écrits hors séquence, actions de thread de journalisation non terminées avant la fin des actions d'événement. (Imaginez un scénario dans lequel vous vous connectez "en commençant à vous connecter à la base de données" et vous plantez ensuite le serveur, l'événement de journal peut ne jamais être écrit même si l'événement s'est produit (!))
Devrait-il être fait d'une manière différente - vous voudrez peut-être regarder le modèle Disruptor car il est presque idéal pour ce scénario
Peut-être que c'est si rapide qu'il ne vaut même pas la peine - pas d'accord. Si la vôtre est une logique «d'application», et que la seule chose que vous faites est d'écrire des journaux de l'activité - alors vous obtiendrez des ordres de grandeur de latence plus faible en déchargeant la journalisation. Si toutefois vous comptez sur un appel SQL DB de 5 secondes pour retourner avant de consigner les instructions 1-2, les avantages sont mitigés.
la source
Je pense que la journalisation est généralement une opération synchrone de par sa nature. Vous voulez enregistrer des choses si elles se produisent ou non en fonction de votre logique, donc pour enregistrer quelque chose, cette chose doit être évaluée en premier.
Cela dit, vous pouvez améliorer les performances de votre application en mettant en cache les journaux, puis en créant un thread et en les enregistrant dans des fichiers lorsque vous avez une opération liée au processeur.
Vous devez identifier vos points de contrôle intelligemment afin de ne pas perdre vos informations de journalisation importantes pendant cette période de cache.
Si vous souhaitez augmenter les performances de vos threads, vous devez équilibrer les opérations d'E / S et les opérations du processeur.
Si vous créez 10 threads qui font tous des IO, vous n'obtiendrez pas d'amélioration des performances.
la source
La journalisation asynchrone est le seul moyen de procéder si vous avez besoin d'une faible latence dans les threads de journalisation. La façon dont cela est fait pour des performances maximales passe par le modèle de perturbateur pour une communication de thread sans verrouillage et sans déchets. Maintenant, si vous souhaitez autoriser plusieurs threads à se connecter simultanément au même fichier, vous devez soit synchroniser les appels de journal et payer le prix en conflit de verrouillage OU utiliser un multiplexeur sans verrouillage. Par exemple, CoralQueue fournit une simple file d'attente de multiplexage comme décrit ci-dessous:
Vous pouvez jeter un œil sur CoralLog qui utilise ces stratégies pour la journalisation asynchrone.
Avertissement: je suis l'un des développeurs de CoralQueue et CoralLog.
la source