feat(puzzle): 使用虚拟线程优化拼图模板批量生成性能

- 将原有的串行模板生成逻辑改为并行处理
- 使用虚拟线程池提升高并发场景下的执行效率
- 通过 CompletableFuture 异步执行每个模板的生成任务
- 保留原有日志记录和异常处理机制
- 统计成功与失败数量并输出汇总日志
This commit is contained in:
2025-12-13 17:38:48 +08:00
parent 83d1096fdb
commit dbee1d9709
2 changed files with 61 additions and 43 deletions

View File

@@ -74,22 +74,31 @@ public class PuzzleGenerationOrchestrator {
// 3. 准备公共动态数据
Map<String, String> baseDynamicData = buildBaseDynamicData(faceId, faceUrl, scenicBasic);
// 4. 遍历所有模板,逐个生成
int successCount = 0;
int failCount = 0;
for (PuzzleTemplateDTO template : templateList) {
try {
generateSingleTemplate(scenicId, faceId, memberId, template, baseDynamicData);
successCount++;
} catch (Exception e) {
log.error("拼图生成失败: scenicId={}, templateCode={}, templateName={}",
scenicId, template.getCode(), template.getName(), e);
failCount++;
}
// 4. 使用虚拟线程池并行生成所有模板
java.util.concurrent.atomic.AtomicInteger successCount = new java.util.concurrent.atomic.AtomicInteger(0);
java.util.concurrent.atomic.AtomicInteger failCount = new java.util.concurrent.atomic.AtomicInteger(0);
try (java.util.concurrent.ExecutorService executor = java.util.concurrent.Executors.newVirtualThreadPerTaskExecutor()) {
// 为每个模板创建一个异步任务
List<java.util.concurrent.CompletableFuture<Void>> futures = templateList.stream()
.map(template -> java.util.concurrent.CompletableFuture.runAsync(() -> {
try {
generateSingleTemplate(scenicId, faceId, memberId, template, baseDynamicData);
successCount.incrementAndGet();
} catch (Exception e) {
log.error("拼图生成失败: scenicId={}, templateCode={}, templateName={}",
scenicId, template.getCode(), template.getName(), e);
failCount.incrementAndGet();
}
}, executor))
.toList();
// 等待所有任务完成
java.util.concurrent.CompletableFuture.allOf(futures.toArray(new java.util.concurrent.CompletableFuture[0])).join();
}
log.info("景区拼图模板批量生成完成: scenicId={}, 总数={}, 成功={}, 失败={}",
scenicId, templateList.size(), successCount, failCount);
scenicId, templateList.size(), successCount.get(), failCount.get());
} catch (Exception e) {
// 异步任务失败不影响主流程,仅记录日志

View File

@@ -390,42 +390,51 @@ public class FaceMatchingOrchestrator {
baseDynamicData.put("scenicText", scenicBasic.getName());
baseDynamicData.put("dateStr", DateUtil.format(new Date(), "yyyy.MM.dd"));
// 遍历所有模板,逐个生成
int successCount = 0;
int failCount = 0;
for (PuzzleTemplateDTO template : templateList) {
try {
log.info("开始生成拼图: scenicId={}, templateCode={}, templateName={}",
scenicId, template.getCode(), template.getName());
// 使用虚拟线程池并行生成所有模板
java.util.concurrent.atomic.AtomicInteger successCount = new java.util.concurrent.atomic.AtomicInteger(0);
java.util.concurrent.atomic.AtomicInteger failCount = new java.util.concurrent.atomic.AtomicInteger(0);
// 构建生成请求
PuzzleGenerateRequest generateRequest = new PuzzleGenerateRequest();
generateRequest.setScenicId(scenicId);
generateRequest.setUserId(memberId);
generateRequest.setFaceId(faceId);
generateRequest.setBusinessType("face_matching");
generateRequest.setTemplateCode(template.getCode());
generateRequest.setOutputFormat("PNG");
generateRequest.setQuality(90);
generateRequest.setDynamicData(new HashMap<>(baseDynamicData));
generateRequest.setRequireRuleMatch(true);
try (java.util.concurrent.ExecutorService executor = java.util.concurrent.Executors.newVirtualThreadPerTaskExecutor()) {
// 为每个模板创建一个异步任务
List<java.util.concurrent.CompletableFuture<Void>> futures = templateList.stream()
.map(template -> java.util.concurrent.CompletableFuture.runAsync(() -> {
try {
log.info("开始生成拼图: scenicId={}, templateCode={}, templateName={}",
scenicId, template.getCode(), template.getName());
// 调用拼图生成服务
PuzzleGenerateResponse response = puzzleGenerateService.generate(generateRequest);
// 构建生成请求
PuzzleGenerateRequest generateRequest = new PuzzleGenerateRequest();
generateRequest.setScenicId(scenicId);
generateRequest.setUserId(memberId);
generateRequest.setFaceId(faceId);
generateRequest.setBusinessType("face_matching");
generateRequest.setTemplateCode(template.getCode());
generateRequest.setOutputFormat("PNG");
generateRequest.setQuality(90);
generateRequest.setDynamicData(new HashMap<>(baseDynamicData));
generateRequest.setRequireRuleMatch(true);
log.info("拼图生成成功: scenicId={}, templateCode={}, imageUrl={}",
scenicId, template.getCode(), response.getImageUrl());
successCount++;
// 调用拼图生成服务
PuzzleGenerateResponse response = puzzleGenerateService.generate(generateRequest);
} catch (Exception e) {
log.error("拼图生成失败: scenicId={}, templateCode={}, templateName={}",
scenicId, template.getCode(), template.getName(), e);
failCount++;
}
log.info("拼图生成成功: scenicId={}, templateCode={}, imageUrl={}",
scenicId, template.getCode(), response.getImageUrl());
successCount.incrementAndGet();
} catch (Exception e) {
log.error("拼图生成失败: scenicId={}, templateCode={}, templateName={}",
scenicId, template.getCode(), template.getName(), e);
failCount.incrementAndGet();
}
}, executor))
.toList();
// 等待所有任务完成
java.util.concurrent.CompletableFuture.allOf(futures.toArray(new java.util.concurrent.CompletableFuture[0])).join();
}
log.info("景区拼图模板批量生成完成: scenicId={}, 总数={}, 成功={}, 失败={}",
scenicId, templateList.size(), successCount, failCount);
log.info("景区拼图模板批量生成完成: scenicId={}, 总数={}, 成功={}, 失败={}",
scenicId, templateList.size(), successCount.get(), failCount.get());
} catch (Exception e) {
// 异步任务失败不影响主流程,仅记录日志