У меня должно быть буферизированное char
поток, в который я пишу в одном потоке и из которого я читал в другом потоке. Прямо сейчас я использую PipedReader и PipedWriter для него, но те классы вызывают проблему производительности: PipedReader делает a wait(1000)
когда его внутренний буфер пуст, который заставляет мое приложение отставать явно.
Была бы некоторая библиотека, которая делает то же самое как PipedReader/PipedWriter, но с лучшей производительностью? Или я должен буду реализовать свои собственные колеса?
Проблема заключалась в том, что когда что-то записывается в PipedWriter, он автоматически не уведомляет PipedReader о том, что есть данные для чтения. Когда кто-то пытается прочитать PipedReader, а буфер пуст, PipedReader зацикливается и ждет, используя вызов wait(1000)
, пока в буфере не появятся данные.
Решением является вызов PipedWriter.flush()
всегда после записи чего-либо в трубу. Все, что делает flush, это вызывает notifyAll()
на читателе. Исправление рассматриваемого кода выглядит следующим образом.
(На мой взгляд, реализация PipedReader/PipedWriter очень похожа на случай преждевременной оптимизации - почему бы не уведомлять об этом при каждой записи? Также читатели ждут в активном цикле, просыпаясь каждую секунду, вместо того, чтобы просыпаться только тогда, когда есть что читать. В коде также есть замечания, что обнаружение потоков читателя/писателя, которое он делает, недостаточно сложное.)
Эта же проблема, похоже, есть и в PipedOutputStream. В моем текущем проекте вызов flush()
вручную невозможен (нельзя модифицировать Commons IO's IOUtils.copy()), поэтому я исправил это, создав низколатентные обертки для классов pipe. Они работают намного лучше, чем оригинальные классы :-)
@ Эско Луонтола, я читал ваш код в пакете sbt, чтобы попытаться понять, что вы делаете.Похоже, вы хотите запустить процесс
и передать ему ввод, а результат действия будет передан в разные места. Это вообще правильно?
Я бы попытался изменить основной цикл в ReaderToWriterCopier
так, чтобы вместо выполнения read ()
- операции блокировки, которая, очевидно, когда PipedReader
вызывает опрос - вы явно ожидаете сброса Writer
в flush
. Из документации ясно, что flush
вызывает уведомление всех Reader
.
Я не знаю, как запустить ваш код, поэтому не могу углубиться в него. Надеюсь это поможет.
Должно быть довольно легко обернуть API потока символов вокруг BlockingQueue
.
Я должен сказать, однако, что кажется довольно извращенным, что PipedReader
будет использовать опрос для ожидания данных. Это где-то задокументировано, или вы каким-то образом это обнаружили?
Я реализовал нечто похожее, и задал вопрос, есть ли у кого-нибудь еще более продуманный и проверенный код.