同时使用ZipOutputStream使用100%的CPU

时间:2017-02-09 08:51:22

标签: java concurrency inputstream cpu-usage zipoutputstream

我正在使用LMS的一项功能,即可快速下载一堆选定的文件和文件夹。我使用ZipOutputStream来防止OutOfMemory问题。

该功能运行良好,但我们已经完成了压力测试,并且当多个用户同时下载拉链时(比如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
        }
    }
}

提前致谢。

1 个答案:

答案 0 :(得分:0)

我用@shmosel告诉的一个简单的黑客来解决它。

private static Semaphore mySemaphore= new Semaphore(ServerConfigurationService.getInt("content.zip.download.maxconcurrentdownloads",5),true);

(...)

ZipOutputStream zipOut = null;
    try
    {
        mySemaphore.acquire();
        ContentCollection collection = ContentHostingService.getCollection(collectionId);

(...)

zipOut.flush();
zipOut.close();
mySemaphore.release();

(...)

这在我的测试服务器中有效。但如果有人有任何异议或任何额外的建议,我将很乐意听到。