java - 我实际上想要对 linux 命名管道的阻塞写入
问题描述
我有一个线程应用程序。在一个线程中,我想将从数据库流式传输的数据写入命名管道,并且如果阅读器(在这种情况下为命令行程序“zip”)无法跟上 java 线程,我希望写入阻塞。进入单个 Zip 文件条目的数据可能大于系统的主内存。
无论在写入命名管道时是否使用 FileOutputStream 或 FileWriter,我都会看到以下行为:写入将缓冲,直到 java 堆被填满,然后实际上将线程减慢到读取器的速度。对于单线程进程,这只是浪费空间,但对于多线程进程,这会让其他线程运行到内存不足异常中。
我看到的唯一剩下的选择是使用 JNA 在 C 中进行阻塞写入。欢迎提出其他建议。
顺便提一句。我让“zip”工具进行压缩的真正原因是 java.util.zip 和 Lingala 的 Zip4J 会用缓冲区填充 RAM。
好的,这是一个精简的小例子。我使用“mkfifo fifo”创建了一个命名管道“fifo”并启动“zip --fifo -fz -v fifo.zip fifo”以在命名管道上设置读取过程块。然后我用 -Xmx32M 启动以下 java 程序。如果没有“Mem Eater”线程,它的行为如上所述。有了它,这个线程将在 OutOfMemoryException 中运行。现在看代码:
import java.io.FileWriter;
import java.util.LinkedList;
import java.util.List;
public class fos {
public static void main(String[] argv) {
if (argv.length != 1) {
System.err.println("Usage is:");
System.err.println("java fos.java <fifo>");
System.exit(-1);
}
String fifoName = argv[0];
startMemConsumerThread();
try (var fifoWriter = new FileWriter(fifoName)) {
for(long i=0L; i< Long.MAX_VALUE; i++)
fifoWriter.write("Hello World! "+i+"\r\n");
} catch (Throwable e) {
e.printStackTrace();
}
}
private static void startMemConsumerThread() {
final int NUM_CHUNKS = 20;
final int CHUNK_SIZE = 1024*1024;
final List< byte[] > chunks = new LinkedList<>();
var t = new Thread("Mem Eater") {
@Override
public void run() {
while (true) {
while (chunks.size() < NUM_CHUNKS)
chunks.add(new byte[CHUNK_SIZE]);
chunks.remove(NUM_CHUNKS % 7);
}
}
};
t.setDaemon(true);
t.start();
}
}
解决方案
我围绕打开、写入、关闭做了一个薄 JNA 包装器,以实现写入的阻塞行为。现在我不再观察到无限的内存消耗,但 Java 堆将增长到配置的最大值,并且 GC 会优雅地处理它。
我必须纠正自己:即使使用 FileWriter.write 也会发生阻塞并且内存消耗是有限的。感谢joni推我!
但是在这个用例中使用 java.util.ZipOutputStream 时,事情就会失控。不过那是另一回事了...
推荐阅读
- r - 通过变量迭代计算预测模型结果
- r - 不能从 R 中压缩目录而不包括完整的文件路径
- asp.net - Azure AD 中的 jwt-bearer 代表授权问题
- html - 使用类更改ul li中的字体颜色
- ansible - Make ansible ignore variable in template when checking changed state
- javascript - Javascript - 按钮的 rowIndex 在表格中不起作用
- kotlin - 有没有办法在 Kotlin 单例对象上隐藏实例变量
- user-interface - JavaFX 聊天窗口,如 Facebook 聊天
- python-3.x - 在 Pandas 中打开 csv 文件后将 int 分配给字符串值
- numpy - 使用 pyspark 创建和操作 numpy 数组并使用数据