Как эффективно использовать Spring Async Task Executor при преобразовании списка больших файлов PDF в изображения - PullRequest
0 голосов
/ 20 мая 2019

У меня есть случай, когда пользователь может загрузить несколько больших файлов PDF на наш сервер, где мы преобразуем их в набор изображений Я думаю, просто подумав, что я создал асинхронный исполнитель для каждого метода преобразования файлов, но я точно не знаю, работает ли он правильно, или моя реализация неэффективна, как я думал.

Я создал асинхронный исполнитель в моем проекте. Использование @Configuration @EnableAsync -> созданный файл конфигурации И пометил мои функции внутри службы с помощью @Async ("asyncExecutor"), которые возвращают CompletableFuture>

Ниже код находится внутри моего контроллера покоя, который возвращает список сохраненных вложений [изображения], преобразованные из файла PDF

//TODO Check mime type
    when(model.extension){

        // TODO all below processes are async
        "pdf" -> {
            list =  powerPointToImageConverter.convertPdfToImages(ByteArrayInputStream(data.content), data.attachment_type!!, principal)
        }

        "ppt" -> {
            list =powerPointToImageConverter.convertPPTToImages(ByteArrayInputStream(data.content), data.attachment_type!!,principal)
        }

        "pptx" -> {
            list = powerPointToImageConverter.convertPPTXToImages(ByteArrayInputStream(data.content), data.attachment_type!!,principal)
        }

        else -> throw FileNotUploadedException()
    }

    if (list.get().isNotEmpty()){
        (thatcourse.docs as PersistentBag).addAll(list.get())
        stRepo.save(thatcourse)
    }

И внутри моего Сервиса у меня есть следующая функция, которая преобразует pdf в набор изображений, сохраняет в db и возвращает результат в случае успеха

 // TODO Convert PPTX into Images
@Async("asyncExecutor")
fun convertPPTXToImages(inputStream:InputStream, attachment_type: AttachmentType, principal: Principal): CompletableFuture<List<BaseFileUploaderAttachment>> {
    log.info("convertPPTXToImages starts")
    try{
        val pptx = XMLSlideShow(inputStream)

        //getting the dimensions and size of the slide
        val pgsize = pptx.pageSize
        val pptxSlide = Arrays.asList<XSLFSlide>(*pptx.slides)

        var outputList:MutableList<BaseFileUploaderAttachment> = arrayListOf()

        for (i in pptxSlide.indices) {
            val img = BufferedImage(pgsize.width, pgsize.height, BufferedImage.TYPE_INT_RGB)

            //render
            pptxSlide[i].draw(createImage(img, pgsize))

            val bytes = convertBuffToBytes(img)

            val attachment = getAttachment(i,attachment_type.toString().toLowerCase().plus(Const.ST_ATTACHMENTS),  attachment_type.code, bytes.size.toLong())

            val filename = attachment.filename + "." + attachment.extension
            val result = fileManagerService.createFile(bytes, filename, attachment.path)
            if (result)
                outputList.add(attachment)

                //creating an image file as output
//            imageFile(i, img)
            }
            outputList = attachmentService.saveAll(outputList, principal).toMutableList()
            log.info("convertPPTXToImages completed")
            return CompletableFuture.completedFuture(outputList)
        }
        catch (ex:Exception){
            throw FileNotUploadedException()
        }

    }

Файл My Config для асинхронного исполнителя

@Configuration
@EnableAsync
class AsyncConfiguration {
    @Bean(name = ["asyncExecutor"])
    fun asyncExecutor(): Executor {
        val executor = ThreadPoolTaskExecutor()
        executor.corePoolSize = 3
        executor.maxPoolSize = 3
        executor.setQueueCapacity(100)
        executor.threadNamePrefix = "AsynchThread-"
        executor.initialize()
        return executor
    }
}

Я много тестировал, загружая файлы большого размера в небольшие. Время отклика другое, очевидно, что оно занимает больше минуты из-за продолжительного времени преобразования и большего количества страниц. Вы можете увидеть логи трех разных запросов на скриншоте ниже Three threads created and working separately

For one request and its too long i just got a small part of it from my log

Мой вопрос заключается в том, как лучше или лучше всего подойти к этому, и что, если я хочу вставить несколько файлов pdf или pptx в цикл, например

attachments.forEach {
        val entity = LearningMaterial()
        var list: CompletableFuture<List<BaseFileUploaderAttachment>>? = null
        var type: LearningMaterialType = LearningMaterialType.OTHER
        when (it.extension) {
            "pdf" -> {
                list = powerPointToImageConverter.convertPdfToImages(it, principal)
                type = LearningMaterialType.PRESENTATION_PDF
            }
            "ppt" -> {
                list = powerPointToImageConverter.convertPPTToImages(it, principal)
                type = LearningMaterialType.PRESENTATION_PPT
            }
            "pptx" -> {
                list = powerPointToImageConverter.convertPPTXToImages(it, principal)
                type = LearningMaterialType.PRESENTATION_PPT
            }
            "doc", "docx" -> {
                type = LearningMaterialType.DOCUMENT_WORD
            }
        }

        entity.mainFile = it
        if (list != null)
            entity.contentList.addAll(list.get())
        else
            entity.downloadable = true
        entity.type = type.code
        learningMaterials.add(entity)
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...