où disposer de StreamWriter si j'en ai besoin pendant toute la durée de vie de l'application?

Where to dispose StreamWriter if I need it during entire application lifetime? I'm going to dispose it in destructor, will that work? I have to dispose to flush data, and I don't want to use AutoFlush feature because from msdn: "You can get better performance by setting AutoFlush to false, assuming that you always call Close (or at least Flush) when you're done writing with a StreamWriter."

Alors devrais-je Dispose dans destructor comme dans le code ci-dessous?

class Log
{
    private static StreamWriter swLog = new StreamWriter("logMAIN.txt");

    static ~Log()
    {
        swLog.Dispose();
    }

    public static void Push(LogItemType type, string message)
    {
        swLog.WriteLine(type + " " + DateTime.Now.TimeOfDay + " " + message);
    }
}

upd instead of Dispose i meant to call Close but it is not improtant in this case because they seems doing exactly the same.

0
Si vous le faites pour la journalisation, envisagez d'utiliser les frameworks de traçage existants (qui font partie de .Net Framework, ou l'un des plus externes tels que Log4Net) qui ont déjà résolu tous les problèmes que vous rencontrez et que vous découvrirez à l'avenir (comme l'accès multi-thread , rotation du journal, erreurs d'E/S, extensibilité ...).
ajouté l'auteur Alexei Levenkov, source
Utilisez simplement File.WriteAllText et ne vous souciez pas de StreamWriter .
ajouté l'auteur Bali C, source

2 Réponses

Vous semblez fonder votre décision de ne pas vider certaines informations sur les performances de MSDN. Ce n'est pas par où je commencerais.

Avez-vous des preuves que l'utilisation d'AutoFlush vous cause des problèmes de performances significatifs ?

Avez-vous envisagé d'atténuer ces problèmes de performance d'une manière différente, par ex. avoir un seul thread écrit dans le StreamWriter , soit rinçage automatique ou rinçage périodique toutes les 20 secondes ou quoi que ce soit?

Vous ne nous avez pas dit quel type d'application vous écrivez, cela ne vous dérange pas - cela peut faire une différence significative en termes de connaissances sur l'arrêt.

Notez également que le code que vous avez donné n'est pas sûr pour les threads. Vous pourriez finir par utiliser le StreamWriter de plusieurs threads simultanément; Je doute que StreamWriter soit particulièrement conçu pour ce scénario.

0
ajouté
certains logs sont multithread, j'utilise lock (this) dans la méthode Push dans ce cas. Je pense que je n'utilise pas les threads de fond (mais j'utilise Tasks .) Merci Jon je pense que je vais utiliser AutoFlush jusqu'à ce que cela devienne un problème
ajouté l'auteur javapowered, source
c'est juste une application console
ajouté l'auteur javapowered, source
pourquoi ne puis-je pas simplement mettre en œuvre une chose aussi simple: "garder le streamwriter ouvert jusqu'à ce que la classe externe soit éliminée, tout rincer sur le disque quand la classe externe est éliminée".
ajouté l'auteur javapowered, source
l'application est utilisée pour le trading HFT. eh oui je ne sors que lorsque l'application s'arrête :) ou qu'entendez-vous par exit points ?
ajouté l'auteur javapowered, source
J'ai de nombreux journaux différents dans mes applications, certains d'entre eux, comme celui-ci, est utilisé à partir d'un seul thread. Probablement AutoFlush sera bien pour moi, mais comme je n'ai pas besoin de journaux immédiatement, je pensais ne pas l'utiliser. Il n'y a aucune raison pour moi d'utiliser AutoFlush et il a été désactivé par défaut dans .NET, j'ai donc décidé d'utiliser le scénario "par défaut".
ajouté l'auteur javapowered, source
@javapowered: "Il n'y a aucune raison pour moi d'utiliser AutoFlush" - enfin, à part le fait que vous voulez vous assurer de ne perdre aucun journal même si votre application est éteinte? Vous toujours n'avez pas expliqué quel type d'application vous écrivez, et si vous avez un point de sortie bien défini ...
ajouté l'auteur Jon Skeet, source
@javapowered: Vous pouvez. Mais vous ne nous avez pas dit quel genre de l'application c'est - application web, client riche, etc. Si vous pouvez dire au bon moment pour disposer de vos journaux, alors - jetez-les alors.
ajouté l'auteur Jon Skeet, source
@javapowered: Ok, enfin, quelques informations. Et avez-vous plusieurs threads, ou est-ce seulement un thread? Si vous avez plusieurs threads, y a-t-il des threads d'arrière-plan? Si vous pouvez vous débarrasser de tout simplement en sortant, ce sera l'approche la plus simple ... bien que cela signifie que IDisposable va probablement se faufiler complètement à travers votre code, juste pour l'enregistrement. Je vous invite toujours à au moins considérer simplement le rinçage automatique ...
ajouté l'auteur Jon Skeet, source

Le problème est vraiment la façon dont le StreamWriter est initialisé. En utilisant un objet régulier comme celui-ci

using (var logger = new Log())
{
    app.Run();
}

Le StreamWriter peut toujours être un champ statique dans la classe Log , mais il est initialisé et éliminé à des moments connus au lieu d'utiliser un initialiseur statique.

Pour que cela fonctionne, vous devez laisser la classe log implémenter l'interface IDisposable et disposer le StreamWriter dans la méthode Dispose comme ceci:

class Log: IDisposable
{
    private static StreamWriter swLog;

    public Log()
    {
       swLog = new StreamWriter("logMAIN.txt");
    }

    public void Dispose()
    {
        swLog.Dispose();
    }

    public static void Push(LogItemType type, string message)
    {
        swLog.WriteLine(type + " " + DateTime.Now.TimeOfDay + " " + message);
    }
}

Notez également comment le Log sera éliminé même si une exception est levée.

0
ajouté
et si j'ai plusieurs (ou douzaines) de logs différents, je devrais écrire beaucoup de imbriqués en utilisant des blocs ?
ajouté l'auteur javapowered, source
@JonSkeet mon mauvais, supprimons simplement statique du destructeur et supposons que cette classe est utilisée à partir d'un seul thread ... hm mais j'ai aussi besoin d'une version multithread
ajouté l'auteur javapowered, source
@vidstige: Le code d'origine ne sera même pas compilé, car il n'y a pas de finaliseur statique. Mais suggérer une solution qui mute une variable statique sur construction n'est pas une bonne réponse, IMO.
ajouté l'auteur Jon Skeet, source
@vidstige: En fait, c'est pire maintenant. Maintenant, si vous avez deux blocs utilisant créant des instances séparées dans différents threads, vous pouvez disposer du StreamWriter dans un thread pendant que vous essayez de l'utiliser dans un autre thread. Aie. Évidemment, si votre application est assez simple pour avoir un point de sortie bien contrôlé, la question est triviale. J'imagine que ce n'est pas le cas, même si le PO n'a pas dit quel genre d'application c'est.
ajouté l'auteur Jon Skeet, source
@javapowered: Maintenant, vous supposez que votre finaliseur sera exécuté avant le finaliseur du flux sous-jacent. Il n'y a aucune garantie de cela. Fondamentalement, vous ne devriez pas utiliser les finaliseurs dans ce cas.
ajouté l'auteur Jon Skeet, source
Vous n'avez pas expliqué comment StreamWriter serait "initialisé et disposé à des points connus dans le temps" - où l'élimination est le point important ici.
ajouté l'auteur Jon Skeet, source
@Jon C'est aussi le problème dans le code original. N'oubliez pas que le finaliseur s'exécute dans son propre thread. La question de l'accès à partir de plusieurs threads ne concerne que vaguement se rapportent à la question quand de disposer du StreamWriter. Mon hypothèse est le contraire comme vous l'avez deviné, l'application a un point de sortie bien défini.
ajouté l'auteur vidstige, source
@Jon vrai. cette partie est, espérons-le, un peu plus claire après l'édition
ajouté l'auteur vidstige, source
Ouais pourquoi pas? Ou créez une nouvelle classe dont la liste de logs est éliminée quand it est éliminé. Une classe, une responsabilité.
ajouté l'auteur vidstige, source