Java 打开多个InputStream的利弊?
在编写关于的问题的代码时,一个想法开始困扰着我,并引出了这个问题,要求纯粹的好奇心/对知识的渴望: 如果我不是一次加载一个Java 打开多个InputStream的利弊?,java,database,memory-management,inputstream,Java,Database,Memory Management,Inputstream,在编写关于的问题的代码时,一个想法开始困扰着我,并引出了这个问题,要求纯粹的好奇心/对知识的渴望: 如果我不是一次加载一个InputStreams(对数据库进行单独的查询),而是在一个查询中加载所有InputStreams,返回一个列表(n,可能是数千个“打开的”)InputStream,我会遇到什么样的缺点 当前(安全)版本:n个查询,一次实例化一个inputStream for (long id : ids){ InputStream in = getMyService().load
InputStream
s(对数据库进行单独的查询),而是在一个查询中加载所有InputStream
s,返回一个列表(n,可能是数千个“打开的”)InputStream
,我会遇到什么样的缺点
当前(安全)版本:n个查询,一次实例化一个inputStream
for (long id : ids){
InputStream in = getMyService().loadStreamById(id);
IOUtils.copyStream(in, out);
in.close();
}
假设版本:一个查询,n个实例化的inputStreams
List<InputStream> streams = getMyService().loadAllStreams();
for (InputStream in : streams){
IOUtils.copyStream(in, out);
in.close();
in = null;
}
List streams=getMyService().loadAllStreams();
对于(InputStream in:streams){
IOUtils.copyream(输入、输出);
in.close();
in=null;
}
第二种方法的优点和缺点是什么,不包括(我假设很少)用于保持多个java InputStream实例化的内存量
它是否会导致某种网络冻结或数据库压力(或锁定,或其他人读/写流指向的同一BLOB字段时出现问题等),而不是多次查询
或者他们是否足够聪明,在被要求提供数据之前几乎看不见,然后
1 query+1000 active stream
可能比1000 query+1 active stream
更好?简单的回答是,您可能会遇到操作系统和/或DBMS的限制
较长的答案取决于特定的操作系统和DBMS,但这里有一些事情需要考虑:
- 在Linux上,任何进程都可以容纳最大数量的打开文件描述符。默认值是/是1024,但增加起来相对容易。这个限制的目的是杀死一个写得不好的进程,因为每个文件/套接字所需的内存量是最小的(在现代机器上)
- 如果open流表示到数据库的单个套接字连接,那么对于单个计算机可以向单个服务器地址/端口打开的客户端套接字的总数有一个硬限制。这是由客户端的动态端口地址范围驱动的,它是16或32k(但可以修改)。此限制适用于计算机上的所有进程,因此一个进程的过度消耗可能会使试图访问同一服务器的其他进程陷入饥饿
- 根据DBMS如何管理用于检索blob的连接,您可能会遇到DBMS强制执行的更小的限制。例如,Oracle默认为每个用户连接总共有50个“游标”(活动检索操作)
除了这些限制之外,如果您的代码是按编写的,您将不会得到任何好处,因为它是按顺序通过连接运行的。如果要使用多个线程进行读取,您可能会看到多个并发连接的一些好处。但是,我仍然会根据需要打开这些连接。而且,为了避免您想到为每个连接生成一个线程(并运行到线程数的物理限制),您可能会在达到任何物理限制之前达到实际的吞吐量限制。我在PostgreSQL中测试了它,它是有效的 由于PostgreSQL似乎没有预定义的最大光标限制,我仍然不知道通过
Java.sql.ResultSet.getBinaryStream(“BLOB_字段”)
将光标/指针从BLOB字段简单分配到JavaInputStream
对象是否被视为一个活动检索操作(我想没有,但谁知道……)
一次加载所有的InputStream
s,类似于selectblob\u fieldfromtable WHERE length(blob\u field)>0
,产生了很长的查询执行时间,以及对二进制内容的快速访问(按顺序,如上所述)
使用200 MB的测试用例,每个测试用例包含20个10 MB的文件:
- 旧方法是每次查询大约1秒,其他操作(读取每个输入流并将其写入输出流等)加上0.XX秒; 总运行时间:35秒
- 实验方法大查询大约22秒,迭代和执行其他操作总共12秒。 总运行时间:34秒
结论 一次读取所有数据要快一点(执行时每30秒大约快1秒), 但这可能会严重导致大查询超时,而不是导致RAM内存泄漏,并可能导致最大光标命中
不要在家里尝试这个,只需一次坚持一个查询…如果打开的文件太多,@Paul Vargas,那会很奇怪,因为这里没有涉及任何文件:)+1,回答很好,谢谢。上面的“形算术版本”的好处在于只需要一个查询,而不是很多查询。由于查询需要几毫秒的时间,避免数千次查询数据库可能会节省几秒钟的时间。关于
50”游标(活动检索操作)
,这是讨论的核心;当我调用rs.getBinaryStream(“field”)
时,我是在实际激活游标,还是只是在稍后请求数据时实例化它以进行延迟激活?