写SpringBoot项目写多了迟早会撞上这么一类问题接口里有个操作特别耗时比如调第三方短信通道、批量发通知、解析上传的文件、导出几十M的报表。用户请求一直卡着转圈数据库连接被占着不放高并发一到请求排队越排越长系统吞吐量肉眼可见地往下掉。这种时候第一反应就是异步调用。SpringBoot 实现异步调用最常用也最省事的做法就是给方法加上 Async 注解配一个自己可控的线程池把耗时任务丢到其他线程去执行主线程立刻返回。这篇文章我把从配置到原理、从返回值处理到异常兜底、再到各种隐蔽大坑全部过一遍给你一份可以直接抄作业的实践方案。1. 先想清楚异步到底在解决什么问题1.1 哪些业务适合用异步第一类是最典型的外部接口调用。发短信、发邮件、推送消息、调第三方风控接口、上报埋点数据这些都是“请求发出去了结果好坏对主流程影响不大”的场景。用户下单成功后短信晚一秒钟到达完全无感可如果主线程傻等短信网关返回一旦通道抖动整个下单接口就被拖慢了。把这类调用从主链路拆出去主线程的响应时间能降一个数量级。第二类是真正的“体力活”。报表生成、大文件解析、视频转码、批量导出单个任务动辄几秒甚至几分钟根本不可能让用户在请求线程里一直等。这类任务天然就该丢到后台线程池慢慢跑跑完把结果落库或者通知用户“任务已完成”。第三类是削峰填谷。秒杀、抢课、投票这类场景瞬时流量很大如果所有请求都同步处理数据库连接池和线程池瞬间就可能被打爆。把非核心的处理放到异步队列里慢慢消费后端压力就能平缓很多这也算是“用空间换时间”的典型思路。不过反过来也要说清楚什么场景别用异步。如果你的接口必须拿到任务结果才能继续比如支付回调要立即返回验签结果或者接口要查询实时库存那就老老实实同步处理就算想快一点也要用 CompletableFuture 做异步编排把结果聚合回来而不是单纯地 fire-and-forget否则用户那边拿不到结果体验更糟。1.2 SpringBoot 里实现异步的几种路子直接 new Thread写起来很爽但是每次请求都创建新线程线程生命周期没人管理资源完全不可控生产环境千万别这么干。手动用 ExecutorService比裸线程好一点但线程池的创建、关闭、异常处理全得自己在业务代码里管理侵入性太强。Async 注解把线程池交给 Spring 容器管理业务方法上标一个注解Spring AOP 帮忙把调用转发到线程池执行代码侵入最小也是我实际生产里最推荐的方式。CompletableFuture适合一组异步任务需要编排、合并、并发执行的场景它可以和 Async 组合使用后面我会专门讲。消息队列如果异步任务要跨系统、跨服务或者需要保证可靠投递和重试那就得引入 MQ这已经超出单应用异步的范畴了。我的建议是同一个应用内部的异步任务优先用 Async 自定义线程池一旦涉及跨系统解耦或者任务绝对不能丢再考虑 MQ。说白了工具选型要看问题的范围别一上来就搬一堆中间件给系统增加不必要的复杂度。2. Async 的完整落地配置从注解到线程池2.1 先开总开关EnableAsyncAsync 本质上是 Spring AOP 在起作用。方法上加了这个注解Spring 会在运行时为对应的 Bean 生成一个代理对象调用方法时先被代理拦截然后把任务丢给指定的线程池执行。但默认情况下这个功能是关闭的你必须先在某个配置类上打开开关Configuration EnableAsync public class AsyncConfig { }EnableAsync 也可以直接加到启动类上但我更习惯单独放在配置类里让功能的边界清楚一点。这里有个关键前提必须记住Async 只能作用于 Spring 容器管理的 Bean 上的 public 方法。如果加在普通内部类的方法上或者方法是 private 的它不会有任何异步效果而是静默地同步执行。这种代码看起来没什么毛病但实际行为完全不符合预期排查起来特别费劲因为日志显示方法确实执行了只是没异步而已。2.2 自己定义线程池这一步千万别偷懒我知道很多人第一次用 Async就是简单加一个注解不配置线程池结果线上突然出现一堆莫名其妙的任务堆积。Spring Boot 默认虽然会提供一个任务执行器但参数不可控任务一多线程就可能膨胀得很快日志里全是一大堆重复的任务名排查时都不知道该看哪个线程。请不要偷懒务必为异步任务专门定义一个线程池。Bean(notifyExecutor) public ThreadPoolTaskExecutor notifyExecutor() { ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor(); executor.setCorePoolSize(4); executor.setMaxPoolSize(8); executor.setQueueCapacity(200); executor.setKeepAliveSeconds(60); executor.setThreadNamePrefix(notify-); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.setWaitForTasksToCompleteOnShutdown(true); executor.setAwaitTerminationSeconds(30); executor.initialize(); return executor; }参数怎么定我的习惯是先用一个粗略公式估算并发任务数约等于 QPS 乘以单任务平均耗时秒再乘一个 1.5 到 2 的冗余系数。比如短信任务平均耗时 300 毫秒预计峰值 QPS 是 50那么需要的并发线程数大约是 50 × 0.3 × 1.5 ≈ 23。这时候可以把核心线程数设为 8最大线程数给到 24队列容量留 200 左右让流量先进队列缓冲队列满了再扩容到最大线程数。注意最大线程数不是越大越好很多问题恰恰是线程太多、上下文切换开销变大接口反而更慢线程池参数最后一定要结合压测微调。如果你不想写配置类Spring Boot 也允许在 application.yml 里通过 spring.task.execution.pool 前缀调整默认线程池参数例如 core-size、max-size、queue-capacity。但这种方式没法定制线程名前缀和拒绝策略所以我自己还是偏向写配置类把线程池和异常处理集中在同一处便于维护。拒绝策略这里我不建议用默认的 AbortPolicy。任务被拒直接抛异常是最容易 “悄悄丢任务” 的写法如果没有兜底这个通知就没了。CallerRunsPolicy 的意思是线程池满了就回到调用线程自己执行虽然会拖慢主线程一点点但至少任务不会丢。生产环境我一般优先选这个只有明确允许丢弃的日志类任务才会考虑 DiscardPolicy。2.3 Async 注解写给方法的特别说明线程池配好了业务方法上标注即可Service public class NotificationService { Async(notifyExecutor) public void sendSms(String phone, String content) { // 模拟调用短信网关 try { Thread.sleep(500); System.out.println(短信已发送给 phone); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }这里有两个细节。第一Async 后面括号里的名字必须和线程池 Bean 的名字一致我这里写的是 notifyExecutor这样即使项目里有多个线程池也不会选错。第二方法返回值要么是 void要么是 Future 或 CompletableFuture不要直接返回一个业务对象。原因很简单真正执行任务的线程不是调用方线程“同步返回一个结果”这件事本身没有意义如果确实需要结果用 CompletableFuture 把结果包起来让调用方自己决定怎么等。还有一点需要反复强调调用方必须是通过另一个 Spring Bean 来调用这个方法。比如 OrderService 注入 NotificationServiceSpring 代理才会生效。同一个类里用 this 自己调自己代理被绕过Async 直接失效这是新手踩得最多的坑后面我会专门展开。3. 返回值怎么处理Future 与 CompletableFuture 的玩法3.1 void 方法的力量在于“不依赖结果”很多场景其实不需要返回值。发短信、写操作日志、上报埋点、清缓存本质就是异步触发执行成功与否不影响主流程void 返回值最简单也最安全。主线程只管把任务丢进线程池剩下的交给线程池。但 void 方法的代价是异常不会回到调用方。如果方法内部没有 try-catch也没有配置全局异步异常处理器Spring 只会把异常打到日志里或者干脆无声无息任务失败了你可能半天都没察觉。所以我在生产项目里给团队定的规矩是所有 void 异步方法内部至少要有一个 try-catch 来记录业务上下文包括任务参数、失败原因、执行耗时方便事后追溯。3.2 需要结果就用 CompletableFuture如果异步任务有返回值别用 Future直接上 CompletableFuture。Future 虽然也能取结果但 API 太弱没法做编排CompletableFuture 提供了 thenApply、thenAccept、allOf 这些好用的方法写起来非常自然。Async(notifyExecutor) public CompletableFutureBoolean checkUserStatus(Long userId) { boolean passed userStatusQuery(userId); return CompletableFuture.completedFuture(passed); }调用方拿到这个 Future可以挂回调CompletableFutureBoolean future userStatusService.checkUserStatus(1001L); future.thenAccept(result - System.out.println(校验结果: result));如果是几个任务并行执行然后聚合结果CompletableFuture.allOf 就很顺手CompletableFutureBoolean statusFuture userStatusService.checkUserStatus(1001L); CompletableFutureListString tagsFuture userTagService.queryTags(1001L); CompletableFutureVoid all CompletableFuture.allOf(statusFuture, tagsFuture); all.thenRun(() - { boolean status statusFuture.join(); ListString tags tagsFuture.join(); System.out.println(status : tags); });这样的代码比“先 new 三个线程再手动 CountDownLatch 等结果”要清晰得多而且异常链条也更完整任何一个 Future 出错都能在回调里感知到。3.3 超时与结果获取别傻等如果调用方真的需要结果获取时一定要加超时。最怕写 future.get() 不带参数线程池里所有线程都在等待别的线程结果万一对方线程池打满或者任务卡住这里就会形成死等直接把调用线程拖死。正确的写法是 future.get(3, TimeUnit.SECONDS)超时就抛 TimeoutException你再决定是重试、降级还是直接返回失败。Java 9 以后 CompletableFuture 还提供 completeOnTimeout 和 orTimeout 方法直接在异步链上调超时效果更直观。比如 orTimeout(2, TimeUnit.SECONDS) 表示最多等两秒超时就把这个 Future 标记为异常完成。这样不用在调用侧手动 get回调链自己就带超时语义代码更简洁。4. 异常处理异步方法的异常到底去哪了4.1 默认行为会让你吓一跳写同步代码时异常会一层层往上抛最终由全局异常处理器兜住。异步方法就不一样。如果方法返回 void异常发生后调用方那个线程早就执行完了根本接不住如果没有配置异步异常处理器Spring 只会在日志里留一行警告任务失败了你可能很久都发现不了。如果方法返回 Future异常会包装在 ExecutionException 里调用方 get 结果的时候才抛出来。所以异步任务有两个铁律。第一所有执行体内部都要有兜底逻辑核心业务异常不能依赖外部机制去兜第二必须配置一个全局异步异常处理器任何没有被内部捕获的异常至少要留下一行带上下文的日志。这两条同时做到线上出问题才不至于两眼一抹黑。4.2 注册全局异步异常处理器实现 AsyncConfigurer 接口即可Configuration EnableAsync public class AsyncConfig implements AsyncConfigurer { Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return (ex, method, params) - { System.err.println(异步方法 [ method.getName() ] 发生异常: ex.getMessage()); System.err.println(方法参数: Arrays.toString(params)); ex.printStackTrace(); }; } }这样配置之后所有 Async void 方法内部逃逸出来的异常都会经过这个处理器统一记录日志。实际生产环境可以把这一段替换成 log.error 加上告警通知比如钉钉、邮件或者日志平台的聚合告警。需要提醒的是这个处理器只负责返回值是 void 的异步方法返回 Future 的异步方法异常要等调用方 get 时才能感知所以返回 Future 时调用方一定不能忘了处理失败分支否则异常链很容易在中途断掉。4.3 方法内部 try-catch最实用的兜底全局异常处理器是最后一道防线我更推荐把主动权掌握在业务代码里。比如发短信这种任务我会在方法内部 try-catch捕获后记录日志、更新任务状态甚至塞进一个重试队列而不是把异常直接抛给全局处理器。原因是通知类任务失败是常态你需要知道具体是哪一步失败、影响的用户是谁、重试了几次这些业务上下文全局异常处理器很难帮你补齐。具体做法其实不复杂写一个异步任务状态表任务开始插入一条记录状态为处理中成功后更新为成功失败则更新为失败并写上错误原因。后台再挂一个补偿调度任务定期扫描失败状态的任务重新执行。这套机制搭配 Async 使用既能享受异步调用的响应速度又能保证任务最终被处理比单纯丢线程池里“听天由命”要稳重得多。5. 高频踩坑自调用、事务、上下文5.1 同一个类里调 Async 方法为什么不起作用这是所有新手必踩的坑。Async 生效靠的是 Spring AOP 代理代理对象在调用方法时才会拦截和转发。你在同一个类的另一个方法里用 this.sendSms() 调用自己这个 this 是普通对象不走代理注解直接失效。代码看起来完全没问题实际上同步阻塞着执行接口还是卡。解决办法很简单把自己注入进来走代理Service public class OrderService { Autowired private OrderService self; public void createOrder() { // 走代理调用异步才生效 self.sendNotify(); } Async(notifyExecutor) public void sendNotify() { // ... } }还有一种办法是通过 AopContext.currentProxy() 拿当前代理对象但需要先开启 exposeProxy我一般在项目里直接注入自身代码更好懂也更容易被后来的同事看懂。顺带提一句如果方法是从 Controller 里直接调的只要当前 Bean 是 Spring 管理的代理一般没问题怕就怕方法内部又出现了一层 this 调用链那个地方就是失效点。5.2 Async 方法挂在事务上会怎样先给结论Transactional 和 Async 同时出现在一个方法上时事务是在异步线程里独立开启的它不会并入调用方那个事务。原因不复杂调用方事务靠 ThreadLocal 绑定数据库连接异步任务在另一个线程执行连接都不是同一个更谈不上一起提交回滚。这就意味着你要是幻想“主事务回滚了异步任务也一起不发短信”那是不可能的。业务上确实需要这种语义时不要依赖调用方事务的状态宁可自己把消息或任务状态先写入数据库等主事务提交成功后再触发异步处理。这其实就是本地消息表模式的雏形把“事务一致性”和“异步解耦”之间的桥搭起来而不是寄希望于线程之间的状态共享。5.3 ThreadLocal 与请求上下文丢失异步线程来自线程池而 ThreadLocal 是线程私有数据容器那些依赖 ThreadLocal 传递的信息跨线程后全都会丢。典型的有三种日志框架 MDC 里的 traceId、Spring Security 的 SecurityContext以及 RequestContextHolder 里的 HttpServletRequest。具体表现就是异步方法里打印的日志没有链路号想拿当前登录用户拿到的却是 null整条排查链路断掉。我的做法是给线程池配一个 TaskDecorator在任务执行前把父线程的 MDC 复制过去执行完再清理executor.setTaskDecorator(runnable - { MapString, String contextMap MDC.getCopyOfContextMap(); return () - { try { if (contextMap ! null) { MDC.setContextMap(contextMap); } runnable.run(); } finally { MDC.clear(); } }; });SecurityContext 同理可以直接用 Spring Security 提供的 DelegatingSecurityContextRunnable或者干脆在 TaskDecorator 里手动复制。总之你要记住一个原则凡是依赖 ThreadLocal 的信息必须显式地传递到异步线程里谁也不会自动帮你搬过去。6. 完整示例一个下单发通知的异步改造6.1 先看懂场景和改造思路假设你有一个下单接口主流程是保存订单、扣减库存、更新会员积分。原来的代码在同一个同步方法里把短信发送、站内信推送都做完了链路耗时长用户点击下单按钮后要等好几秒。改造的思路很清晰把通知类操作移到单独的 NotificationService加上 Async 注解主线程处理完核心业务后直接返回短信和站内信在线程池里异步执行。这其实是很多中后台系统的典型优化路径把“核心链路”和“周边链路”做物理隔离核心链路保证响应速度周边链路保证最终执行两边互不拖累。下面我给出一份可以直接跑起来的最小代码骨架。6.2 完整代码骨架异步配置类Configuration EnableAsync public class AsyncConfig { Bean(notifyExecutor) public ThreadPoolTaskExecutor notifyExecutor() { ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor(); executor.setCorePoolSize(4); executor.setMaxPoolSize(8); executor.setQueueCapacity(200); executor.setThreadNamePrefix(notify-); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.setWaitForTasksToCompleteOnShutdown(true); executor.setAwaitTerminationSeconds(30); executor.initialize(); return executor; } }通知服务Service public class NotificationService { Async(notifyExecutor) public void sendSms(String phone, String content) { try { smsGateway.send(phone, content); System.out.println(短信发送成功: phone); } catch (Exception e) { System.err.println(短信发送失败: phone , e.getMessage()); // 可在此记录任务状态等待补偿 } } Async(notifyExecutor) public void sendInternalMessage(Long userId, String title, String content) { // 写站内信逻辑 } }主业务服务Service public class OrderAppService { private final OrderRepository orderRepository; private final NotificationService notificationService; public OrderAppService(OrderRepository orderRepository, NotificationService notificationService) { this.orderRepository orderRepository; this.notificationService notificationService; } public String createOrder(OrderDTO dto) { Order order new Order(); order.setUserId(dto.getUserId()); order.setAmount(dto.getAmount()); orderRepository.save(order); notificationService.sendSms(dto.getPhone(), 您的订单 order.getId() 已创建成功); notificationService.sendInternalMessage(dto.getUserId(), 订单通知, 您的订单已创建); return order.getId(); } }一个下单接口就拆成了“同步核心逻辑 异步通知逻辑”。注意这里的 NotificationService 是通过构造器注入的Spring 注入的是代理对象所以 Async 能生效。如果你用了字段注入效果一样但构造器注入在单元测试里更容易替换我建议保持一致。还要提醒一个细节如果线程池配了 setWaitForTasksToCompleteOnShutdown(true)应用关闭时会等待任务执行完毕配合 awaitTerminationSeconds 设置最长等待时间避免服务重启过程中异步任务被硬生生截断。这个配置对消息通知、任务处理类的异步场景非常重要。6.3 异步方法测试不要直接断言结果异步方法一执行测试线程不会等它跑完直接断言输出很容易出现“偶发失败”第一次跑通过第二次就挂。最简单的方案是用 CountDownLatchCountDownLatch latch new CountDownLatch(1); smsGateway.whenComplete((ok, ex) - latch.countDown()); notificationService.sendSms(13800000000, hello); boolean completed latch.await(2, TimeUnit.SECONDS); assertTrue(completed);如果方法返回 CompletableFuture省事很多直接 future.get(3, TimeUnit.SECONDS) 等结果断言即可。要跑更复杂的异步测试我会用 Awaitility 这个库写“最多等 5 秒直到条件成立”的测试比固定 sleep 稳定得多也不会动不动就多等好几秒。7. 问题速查表与几条实战心得7.1 高频问题速查表问题现象可能原因解决方案Async 不生效缺少 EnableAsync在配置类上加 EnableAsyncAsync 不生效同类调用this 直接调用代理被绕过注入自身或拆到另一个 Bean异步方法从未执行方法不是 public改成 public线程数暴涨或任务堆积线程池参数不合理显式定义 core/max/queue压测后调整异步异常没有日志方法返回 void异常被吞实现 AsyncUncaughtExceptionHandler事务不一起回滚异步线程是独立事务不要让异步任务依赖主事务traceId / 登录用户丢失ThreadLocal 不跨线程用 TaskDecorator 复制 MDC服务重启时任务丢失没有优雅停机配置开启 waitForTasksToCompleteOnShutdown7.2 几条实战心得在我实际接触的项目里Async 用崩的情况十有八九不是注解本身的问题而是不懂“代理机制”和“线程池资源边界”。我个人的固定动作是用到 Async 的项目一定先建一个独立的配置类把线程池、异常处理器、TaskDecorator 全部集中写在一起所有异步方法必须带线程池名不裸写 Async所有异步方法内部至少有一个 try-catch 用于记录业务日志。这三条看起来基础但真能省掉大量线上排查时间。线程池参数不要迷信网上推荐的模板。先按业务压测数据定初始值然后持续观察队列积压数量和线程池活跃度再慢慢微调。我见过一个项目把 maxPoolSize 配到 200高峰期线程上下文切换开销比业务本身还大接口反而更慢。线程池是有限资源配参数的目标是“够用且留有余量”不是“越大越好”。最后分享一个小技巧异步任务多的项目最好把线程池的活跃线程数、队列长度、拒绝次数接上监控。线程池不像普通接口有明确的响应时间它的健康度是缓慢变化的等你在日志里发现问题时任务已经堆积很久了。我有一次排查线上短信延迟就是靠着队列积压数量的监控曲线定位到某台机器线程池参数被改坏导致的而应用日志本身完全看不出来。这套“配置统一、参数显式、异常兜底、监控护航”的组合才是 Async 在 SpringBoot 项目里真正能稳定跑起来的底层逻辑。
企业数字化 ERP 产品动态
相关推荐
用ChatGPT+Python+FFmpeg重构短视频三秒模型流水线 1. 这不是“AI写脚本”,而是用ChatGPT重构短视频内容生产流水线你刷到过那种视频吗?前0.8秒就让你手指悬停、瞳孔放大——不是靠美女或爆炸,而是一句“别划走,你刚点进来的那个动作,暴露了你的决策盲区”;或… · 2026/9/26 23:38:22
编码 Agent 实战指南:从任务拆解到代码审查,真正用好 AI 编程助手 这几年 AI 辅助编程的热度一波接一波,但大多数教程还停留在“教你怎么让 AI 写一段代码”的层面。吴恩达最新发布的《Using Coding Agents》公开课,却把角度拨到了另一个方向:与其琢磨提示词,不如先把开发任务当成一个可拆解的工程… · 2026/9/26 23:38:22
嘉兴网站建设维护避坑指南:3个实操案例解析建站报价 嘉兴网站建设维护避坑指南:3个实操案例解析建站报价 自己不会代码,却想尽快上线网站,这是很多嘉兴企业主的常态。找外包怕被坑,自己折腾又没头绪,盯着那些花里胡哨的 建站报价 单,心里直打鼓。… · 2026/9/27 0:14:30
个人做网站备案吗?3步避坑指南+保姆级建站教程 个人做网站备案吗?3步避坑指南+保姆级建站教程 找建站公司怕被坑高价,交钱后才发现备案还要另外收费?这种“隐形消费”在行业里太常见了。很多个人站长或者刚起步的创业者,以为买了域名和服务器就能直接上线,结果卡在备案环节,不仅耽误时间,还可能因… · 2026/9/27 0:14:12
3个坑避开了,php能用着手机网站开发对比评测才靠谱 3个坑避开了,php能用着手机网站开发对比评测才靠谱 网站做好了没人访问,这才是最让人头疼的事。很多老板花几万块做个站,上线一个月后台看数据,日活个位数,甚至为零。别急着怪推广,先回头看看技术底子。最近做了一圈 php能用着手机网站开发… · 2026/9/27 0:14:00
设计网站会员哪个好用?3款建站工具源码下载实测对比 设计网站会员哪个好用?3款建站工具源码下载实测对比 想做个网站,打开浏览器搜“建站”,满屏都是“零代码”、“拖拽式”。结果点进去一看,要么只能改改颜色,要么连个后台管理都没有。自己不会代码想做网站,是不是觉得特别绝望?别急,很多同行都卡在这… · 2026/9/27 0:14:00
拒绝丑模板!在门户网站管理建设工作讲话图解步骤全解 拒绝丑模板!在门户网站管理建设工作讲话图解步骤全解 别再对着那个一眼假的 Bootstrap 模板抓头了,真的,模板网站太丑不够用是大多数创业团队负责人的噩梦。你花大价钱买的“企业级解决方案”,上线后客户第一反应往往是:“这网站是十年前的吧… · 2026/9/27 0:12:39
企业网站seo排名优化哪家好?5步实操避坑指南 企业网站seo排名优化哪家好?5步实操避坑指南 模板网站太丑且功能僵化,根本撑不起业务需求,这时候大家最纠结的就是企业网站seo排名优化哪家好,怕被割韭菜。… · 2026/9/27 0:12:26
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01