【发布时间】:2017-02-09 08:51:21
【问题描述】:
我正在为 LMS 开发一项功能,以即时以 zip 格式下载一堆选定的文件和文件夹。我使用 ZipOutputStream 来防止 OutOfMemory 问题。
该功能运行良好,但我们进行了压力测试,当多个用户同时下载 zip 时(假设 10 个用户每个压缩 100 MB),4 个 CPU 中有 4 个达到 100% 的负载,直到创建拉链。我们的系统管理员认为这是不可接受的。
我想知道是否有某种机制可以使 ZipOutputStream 使用更少的系统资源,无论它是否需要更多时间才能完成。
我当前的代码:
protected void compressResource(ZipOutputStream zipOut, String collectionId, String rootFolderName, String resourceId) throws Exception
{
if (ContentHostingService.isCollection(resourceId))
{
try
{
ContentCollection collection = ContentHostingService.getCollection(resourceId);
List<String> children = collection.getMembers();
if(children != null)
{
for(int i = children.size() - 1; i >= 0; i--)
{
String child = children.get(i);
compressResource(zipOut,collectionId,rootFolderName,child);
}
}
}
catch (PermissionException e)
{
//Ignore
}
}
else
{
try
{
ContentResource resource = ContentHostingService.getResource(resourceId);
String displayName = isolateName(resource.getId());
displayName = escapeInvalidCharsEntry(displayName);
InputStream content = resource.streamContent();
byte data[] = new byte[1024 * 10];
BufferedInputStream bContent = null;
try
{
bContent = new BufferedInputStream(content, data.length);
String entryName = (resource.getContainingCollection().getId() + displayName);
entryName=entryName.replace(collectionId,rootFolderName+"/");
entryName = escapeInvalidCharsEntry(entryName);
ZipEntry resourceEntry = new ZipEntry(entryName);
zipOut.putNextEntry(resourceEntry); //A duplicate entry throw ZipException here.
int bCount = -1;
while ((bCount = bContent.read(data, 0, data.length)) != -1)
{
zipOut.write(data, 0, bCount);
}
try
{
zipOut.closeEntry();
}
catch (IOException ioException)
{
logger.error("IOException when closing zip file entry",ioException);
}
}
catch (IllegalArgumentException iException)
{
logger.error("IllegalArgumentException while creating zip file",iException);
}
catch (java.util.zip.ZipException e)
{
//Duplicate entry: ignore and continue.
try
{
zipOut.closeEntry();
}
catch (IOException ioException)
{
logger.error("IOException when closing zip file entry",ioException);
}
}
finally
{
if (bContent != null)
{
try
{
bContent.close();
}
catch (IOException ioException)
{
logger.error("IOException when closing zip file",ioException);
}
}
}
}
catch (PermissionException e)
{
//Ignore
}
}
}
提前致谢。
【问题讨论】:
-
可以使用信号量来限制并发用户数。
-
不允许同时发生这么多并发的 zip 进程。使用 executor 执行 ziptask,您可以调整用于它们的线程数。
-
考虑到你正在控制读写进程,
ZipOutputStream与你的问题无关,你可以放置OutputStream,任务不会改变。基本上你的问题类似于this one。 -
@user3707125 除了
OutputStream是 I/O 绑定的,ZipOutputStream可以是计算绑定的。 -
@OP 如何使用
ZipOutputStream防止OutOfMemoryErrors?
标签: java concurrency inputstream cpu-usage zipoutputstream