2010-05-16 6 views
7

Je dois avoir un flux char tamponné, dans lequel j'écris dans un fil et à partir de laquelle je lis dans un autre fil. Right now J'utilise PipedReader et PipedWriter pour cela, mais ces classes causent un problème de performances: PipedReader effectue un wait(1000) lorsque son tampon interne est vide, ce qui provoque un retard visible de l'application.Meilleure alternative pour PipedReader/PipedWriter?

Y aurait-il une bibliothèque qui fasse la même chose que PipedReader/PipedWriter, mais avec de meilleures performances? Ou devrais-je mettre en place mes propres roues?

+0

Cela peut ne pas être ce que vous voulez, mais votre thread d'écriture pourrait-il notifier le fil de lecture après avoir écrit quelque chose? Et le fil de lecture continuera à lire pendant que 'ready()' est vrai, puis dormira quand ce n'est pas le cas? – Phil

+0

Pourriez-vous nous indiquer votre code, s'il vous plaît?Le 'wait (1000)' ne devrait pas être le problème, parce que l'auteur notifie le lecteur quand quelque chose est écrit. Le lecteur s'échappe alors de son attente(). – tangens

+0

Merci, Phil. Je ne suis pas à la maison maintenant, donc je ne peux pas le tester, mais basé sur le code source PipedWriter.flush() apparaît pour informer les lecteurs. Je vais essayer plus tard aujourd'hui. –

Répondre

5

Le problème était que lorsqu'un élément est écrit dans le PipedWriter, il n'indique pas automatiquement à PipedReader qu'il y a des données à lire. Lorsque vous essayez de lire PipedReader et que le tampon est vide, PipedReader boucle et attend en utilisant un appel wait(1000) jusqu'à ce que le tampon ait des données.

La solution est d'appeler PipedWriter.flush() toujours après avoir écrit quelque chose sur le tuyau. Tout ce que la chasse d'eau est appelez notifyAll() sur le lecteur. La correction du code en question looks like this.

(Pour moi, l'implémentation de PipedReader/PipedWriter ressemble beaucoup à une optimisation prématurée - pourquoi ne pas notifierAll sur chaque écriture? Aussi les lecteurs attendent dans une boucle active, se réveillant chaque seconde, au lieu de se réveiller Le code contient aussi quelques commentaires, que la détection de thread de lecteur/graveur n'est pas assez sophistiquée.)

Ce même problème semble être également dans PipedOutputStream. Dans mon projet actuel appelant flush() manuellement n'est pas possible (ne peut pas modifier IOUtils.copy() Commons IO's), donc je l'ai corrigé en créant low-latency wrappers pour les classes de tuyau. Ils fonctionnent beaucoup mieux que les classes originales. :-)

1

Il devrait être assez facile d'enrouler un API de flux char autour de BlockingQueue.

Je dois dire, cependant, qu'il semble assez pervers que PipedReader utiliserait l'interrogation pour attendre les données. Est-ce documenté quelque part, ou l'avez-vous découvert par vous-même?

+0

Je pense que vous vouliez faire un lien vers "http://java.sun.com/javase/6/docs/api/java/util/concurrent/BlockingQueue.html" – Phil

+0

Oui, c'est mon plan B, si je ne peux pas trouver une classe qui fait déjà ce dont j'ai besoin. –

+0

Merci Phil. J'étais trop rapide sur le tirage avec ma recherche Google. :-) –

0

J'ai mis en œuvre quelque chose d'un peu similaire, et asked a question si quelqu'un d'autre avait un code mieux pensé et testé.

1

@Esko Luontola, J'ai lu votre code dans le paquet sbt pour essayer de comprendre ce que vous faites. Il semble que vous voulez démarrer un Process et lui transmettre une entrée, et que le résultat de l'action soit diffusé à différents endroits. Est-ce que c'est correct?

Je voudrais essayer de modifier la boucle principale ReaderToWriterCopier de sorte qu'au lieu de faire une read() - une opération de blocage qui apparemment lorsqu'un PipedReader est impliqué provoque l'interrogation - vous attendez explicitement la Writer-flush. La documentation indique clairement que flush provoque la notification de Reader s. Je ne suis pas sûr de savoir comment exécuter votre code, donc je ne peux pas approfondir. J'espère que cela t'aides.

+0

Mon cas d'utilisation est qu'il y a plusieurs lecteurs pour ce qu'un 'processus' imprime, et chacun de ces lecteurs a besoin de sa propre copie du flux, à partir du moment courant et se terminant lorsque le lecteur est fermé. Différents lecteurs ne se touchent pas. Celui qui lit le PipedReader est par exemple 'OutputReader.waitForOutput()'. L'auteur est 'ReaderToWriterCopier'. Le programme principal est 'SbtRunner', et les sources de test ont' SbtRunnerTester' qui l'utilise. SBT signifie http://code.google.com/p/simple-build-tool/ –

Questions connexes