当前位置: 首页 > article >正文

模拟消息队列的消费逻辑-Java

分享一个大牛的人工智能教程。零基础通俗易懂风趣幽默希望你也加入到人工智能的队伍中来请轻击人工智能教程​​​​​https://www.captainai.net/troubleshooter这是一个生产级消息队列消费逻辑模拟重点突出线程模型、可靠性保证、背压控制、顺序消费、以及如何测试验证。一、需求澄清第一步你需要先问清楚场景消费语义最多一次At-most-once、至少一次At-least-once、精确一次Exactly-once顺序要求全局有序还是分区有序消息类型普通消息、延迟消息、事务消息异常处理消费失败后重试、死信、还是跳过性能指标预期QPS、消息大小例如我假设需要实现至少一次消费语义 分区有序支持重试死信用多线程模型提升吞吐。这是最经典的中间态设计。二、核心架构设计先画图再编码[生产者] → [Queue/Broker] → [Consumer Group] ↓ [Worker Pool] (多线程拉取) ↓ [Message Processor] [Ack机制] ↓ (失败时) [Retry Queue] → [Dead Letter Queue]三、完整Java实现1. 消息模型// Message.java import java.time.Instant; import java.util.UUID; public class Message { private final String id; private final String topic; private final String key; // 用于分区 private final byte[] body; private final Instant timestamp; private int retryCount; public Message(String topic, String key, byte[] body) { this.id UUID.randomUUID().toString(); this.topic topic; this.key key; this.body body; this.timestamp Instant.now(); this.retryCount 0; } // Getters and setters public String getId() { return id; } public String getTopic() { return topic; } public String getKey() { return key; } public byte[] getBody() { return body; } public Instant getTimestamp() { return timestamp; } public int getRetryCount() { return retryCount; } public void incrementRetry() { retryCount; } }2. 消费接口定义// MessageConsumer.java FunctionalInterface public interface MessageConsumer { /** * 消费消息 * return true表示消费成功false表示失败需重试 */ boolean consume(Message message); }3. 核心消费引擎// MessageQueueConsumer.java import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReentrantLock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 模拟消息队列消费逻辑 * 特性 * - 线程池并发消费 * - 分区有序同一key的消息顺序处理 * - 失败重试 死信队列 * - 优雅关闭 */ public class MessageQueueConsumer { private static final Logger log LoggerFactory.getLogger(MessageQueueConsumer.class); private final String consumerGroup; private final MessageConsumer consumer; private final int concurrency; // 并发消费线程数 private final int maxRetries; // 最大重试次数 private final long retryDelayMs; // 重试延迟 private final int queueCapacity; // 内部队列容量 // 核心组件 private final BlockingQueueMessage messageQueue; private final ExecutorService workerPool; private final ScheduledExecutorService retryScheduler; private final AtomicBoolean running; private final ConcurrentHashMapString, ReentrantLock partitionLocks; // 死信队列 private final BlockingQueueMessage deadLetterQueue; // 监控指标 private final AtomicLong processedCount; private final AtomicLong successCount; private final AtomicLong failureCount; private final AtomicLong retryCount; public MessageQueueConsumer(String consumerGroup, MessageConsumer consumer, int concurrency, int maxRetries, long retryDelayMs) { this(consumerGroup, consumer, concurrency, maxRetries, retryDelayMs, 10000); } public MessageQueueConsumer(String consumerGroup, MessageConsumer consumer, int concurrency, int maxRetries, long retryDelayMs, int queueCapacity) { this.consumerGroup consumerGroup; this.consumer consumer; this.concurrency concurrency; this.maxRetries maxRetries; this.retryDelayMs retryDelayMs; this.queueCapacity queueCapacity; this.messageQueue new LinkedBlockingQueue(queueCapacity); this.workerPool Executors.newFixedThreadPool(concurrency); this.retryScheduler Executors.newScheduledThreadPool(concurrency / 2); this.running new AtomicBoolean(true); this.partitionLocks new ConcurrentHashMap(); this.deadLetterQueue new LinkedBlockingQueue(); this.processedCount new AtomicLong(0); this.successCount new AtomicLong(0); this.failureCount new AtomicLong(0); this.retryCount new AtomicLong(0); startWorkers(); } /** * 提交消息到消费队列 */ public void submit(Message message) { try { messageQueue.put(message); log.debug(Message submitted to queue: {}, message.getId()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); log.error(Failed to submit message: {}, message.getId(), e); } } /** * 批量提交消息 */ public void submitAll(ListMessage messages) { for (Message msg : messages) { submit(msg); } } /** * 启动工作线程 */ private void startWorkers() { for (int i 0; i concurrency; i) { workerPool.submit(this::consumeLoop); } log.info(Consumer started with {} workers, concurrency); } /** * 主消费循环 */ private void consumeLoop() { while (running.get()) { try { Message message messageQueue.poll(100, TimeUnit.MILLISECONDS); if (message null) { continue; } // 保证分区有序 processWithPartitionOrder(message); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } } /** * 保证同一key的消息顺序处理 */ private void processWithPartitionOrder(Message message) { String lockKey message.getKey() ! null ? message.getKey() : message.getTopic(); ReentrantLock lock partitionLocks.computeIfAbsent(lockKey, k - new ReentrantLock()); lock.lock(); try { processMessage(message); } finally { lock.unlock(); } } /** * 实际消费逻辑带重试 */ private void processMessage(Message message) { processedCount.incrementAndGet(); try { boolean success consumer.consume(message); if (success) { successCount.incrementAndGet(); log.debug(Message consumed successfully: {}, message.getId()); } else { handleFailure(message); } } catch (Exception e) { log.error(Consumer threw exception for message: {}, message.getId(), e); handleFailure(message); } } /** * 处理消费失败 */ private void handleFailure(Message message) { failureCount.incrementAndGet(); if (message.getRetryCount() maxRetries) { // 需要重试 message.incrementRetry(); retryCount.incrementAndGet(); long delay calculateBackoffDelay(message.getRetryCount()); log.warn(Message {} failed (retry {}/{}), retrying in {}ms, message.getId(), message.getRetryCount(), maxRetries, delay); retryScheduler.schedule(() - { if (running.get()) { submit(message); } }, delay, TimeUnit.MILLISECONDS); } else { // 超过最大重试次数进死信队列 log.error(Message {} exceeded max retries, moving to DLQ, message.getId()); deadLetterQueue.offer(message); } } /** * 指数退避 抖动 */ private long calculateBackoffDelay(int retryCount) { long baseDelay retryDelayMs * (long) Math.pow(2, retryCount - 1); long jitter (long) (baseDelay * 0.1 * Math.random()); return Math.min(baseDelay jitter, 30000); // 最大30秒 } /** * 优雅关闭 */ public void shutdown() { log.info(Shutting down consumer...); running.set(false); workerPool.shutdown(); retryScheduler.shutdown(); try { if (!workerPool.awaitTermination(30, TimeUnit.SECONDS)) { workerPool.shutdownNow(); } if (!retryScheduler.awaitTermination(30, TimeUnit.SECONDS)) { retryScheduler.shutdownNow(); } } catch (InterruptedException e) { workerPool.shutdownNow(); retryScheduler.shutdownNow(); Thread.currentThread().interrupt(); } log.info(Consumer shutdown complete. Stats: processed{}, success{}, failure{}, retry{}, dlq{}, processedCount.get(), successCount.get(), failureCount.get(), retryCount.get(), deadLetterQueue.size()); } /** * 获取死信队列中的消息用于人工处理 */ public ListMessage getDeadLetters() { ListMessage deadLetters new ArrayList(); deadLetterQueue.drainTo(deadLetters); return deadLetters; } /** * 获取消费统计信息 */ public ConsumerStats getStats() { return new ConsumerStats( processedCount.get(), successCount.get(), failureCount.get(), retryCount.get(), deadLetterQueue.size(), messageQueue.size() ); } public static class ConsumerStats { private final long processed; private final long success; private final long failure; private final long retry; private final int deadLetterSize; private final int pendingSize; public ConsumerStats(long processed, long success, long failure, long retry, int deadLetterSize, int pendingSize) { this.processed processed; this.success success; this.failure failure; this.retry retry; this.deadLetterSize deadLetterSize; this.pendingSize pendingSize; } Override public String toString() { return String.format(Stats{processed%d, success%d, failure%d, retry%d, dlq%d, pending%d}, processed, success, failure, retry, deadLetterSize, pendingSize); } } }4. 背压控制版本高级特性// BackpressuredConsumer.java - 简化版 /** * 支持背压的消费者当下游处理不过来时自动限流 */ public class BackpressuredConsumer extends MessageQueueConsumer { private final Semaphore backpressureSemaphore; private final int maxInflight; public BackpressuredConsumer(String consumerGroup, MessageConsumer consumer, int concurrency, int maxRetries, long retryDelayMs, int maxInflight) { super(consumerGroup, consumer, concurrency, maxRetries, retryDelayMs); this.maxInflight maxInflight; this.backpressureSemaphore new Semaphore(maxInflight); } Override private void processMessage(Message message) { try { backpressureSemaphore.acquire(); try { super.processMessage(message); } finally { backpressureSemaphore.release(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }四、测试策略重点1. 基础功能测试Test void testBasicConsumption() throws InterruptedException { CountDownLatch latch new CountDownLatch(10); MessageConsumer mockConsumer msg - { latch.countDown(); return true; }; MessageQueueConsumer consumer new MessageQueueConsumer( test-group, mockConsumer, 2, 3, 100 ); for (int i 0; i 10; i) { consumer.submit(new Message(topic, key, (msg i).getBytes())); } assertTrue(latch.await(5, TimeUnit.SECONDS)); ConsumerStats stats consumer.getStats(); assertEquals(10, stats.getProcessed()); assertEquals(10, stats.getSuccess()); consumer.shutdown(); }2. 重试与死信测试Test void testRetryAndDeadLetter() throws InterruptedException { AtomicInteger attemptCount new AtomicInteger(0); MessageConsumer failingConsumer msg - { int attempt attemptCount.incrementAndGet(); return attempt 2; // 第3次成功 }; MessageQueueConsumer consumer new MessageQueueConsumer( test-group, failingConsumer, 1, 2, 10 // 最多重试2次 ); consumer.submit(new Message(topic, key, test.getBytes())); Thread.sleep(500); // 等待重试完成 ConsumerStats stats consumer.getStats(); assertEquals(1, stats.getProcessed()); // 只有1条消息 assertEquals(0, stats.getSuccess()); // 最终失败 assertEquals(1, stats.getDeadLetterSize()); // 进死信队列 assertEquals(2, stats.getRetry()); // 重试了2次 consumer.shutdown(); }3. 分区有序性测试关键Test void testPartitionOrdering() throws InterruptedException { ListInteger consumedOrder Collections.synchronizedList(new ArrayList()); MessageConsumer consumer msg - { int seq Integer.parseInt(new String(msg.getBody())); consumedOrder.add(seq); return true; }; MessageQueueConsumer queueConsumer new MessageQueueConsumer( test-group, consumer, 4, 0, 0 ); // 向两个不同key发送乱序消息 // key1: 1,2,3,4 // key2: 100,200,300 for (int i 1; i 4; i) { queueConsumer.submit(new Message(topic, key1, String.valueOf(i).getBytes())); } for (int i 100; i 300; i 100) { queueConsumer.submit(new Message(topic, key2, String.valueOf(i).getBytes())); } Thread.sleep(1000); // 验证每个分区内部的顺序 ListInteger key1Order consumedOrder.stream() .filter(n - n 4) .collect(Collectors.toList()); ListInteger key2Order consumedOrder.stream() .filter(n - n 100) .collect(Collectors.toList()); assertEquals(Arrays.asList(1,2,3,4), key1Order); assertEquals(Arrays.asList(100,200,300), key2Order); queueConsumer.shutdown(); }4. 背压与限流测试Test void testBackpressure() throws InterruptedException { AtomicInteger processingFlag new AtomicInteger(0); CountDownLatch processingStarted new CountDownLatch(1); MessageConsumer slowConsumer msg - { processingStarted.countDown(); processingFlag.incrementAndGet(); Thread.sleep(2000); // 模拟慢消费 return true; }; BackpressuredConsumer consumer new BackpressuredConsumer( test-group, slowConsumer, 1, 0, 0, 2 // 最多2个inflight ); // 快速提交100条消息 for (int i 0; i 100; i) { consumer.submit(new Message(topic, key, (msg i).getBytes())); } processingStarted.await(); // 验证内部队列已满背压生效 ConsumerStats stats consumer.getStats(); assertTrue(stats.getPendingSize() 100); // 队列应该有积压 consumer.shutdown(); }5. 并发安全性测试Test void testConcurrentSubmit() throws InterruptedException { MessageQueueConsumer consumer new MessageQueueConsumer( test-group, msg - true, 10, 0, 0 ); int threadCount 50; int messagesPerThread 1000; ExecutorService executor Executors.newFixedThreadPool(threadCount); CountDownLatch latch new CountDownLatch(threadCount); for (int t 0; t threadCount; t) { executor.submit(() - { for (int i 0; i messagesPerThread; i) { consumer.submit(new Message(topic, key i % 100, (msg i).getBytes())); } latch.countDown(); }); } latch.await(30, TimeUnit.SECONDS); Thread.sleep(2000); // 等待消费完成 ConsumerStats stats consumer.getStats(); assertEquals(threadCount * messagesPerThread, stats.getProcessed()); executor.shutdown(); consumer.shutdown(); }6. 性能基准测试Test void benchmarkThroughput() { MessageQueueConsumer consumer new MessageQueueConsumer( benchmark, msg - true, 8, 0, 0, 100000 ); int messageCount 500_000; long start System.nanoTime(); for (int i 0; i messageCount; i) { consumer.submit(new Message(topic, key (i % 100), (msg i).getBytes())); } // 等待消费完成 while (consumer.getStats().getProcessed() messageCount) { Thread.sleep(100); } long duration System.nanoTime() - start; double throughput messageCount * 1000.0 / (duration / 1_000_000); System.out.printf(Throughput: %.2f msg/sec%n, throughput); consumer.shutdown(); }五、进阶问题Q1如何保证Exactly-Once语义回答At-least-once 幂等消费。可以在Message中加入全局唯一ID下游系统用Redis或DB去重表记录已处理的ID。实现支持扩展示例如public class ExactlyOnceConsumer extends MessageQueueConsumer { private final SetString processedIds ConcurrentHashMap.newKeySet(); Override protected boolean tryConsume(Message message) { if (processedIds.contains(message.getId())) { return true; // 已处理过直接返回成功 } boolean success super.tryConsume(message); if (success) { processedIds.add(message.getId()); } return success; } }Q2消息积压时如何处理回答动态扩缩容监控队列长度超过阈值时自动增加worker线程数优先级队列高优消息优先处理流量控制发送端限流避免消费端被压垮分片扩展增加更多的分区通过水平扩展消费实例Q3如何测试消息不会丢失回答我会设计故障注入测试在消费过程中随机kill consumer线程模拟网络中断、DB连接超时验证重试机制是否正确触发消息最终是否被处理使用Chaos Monkey框架Q4如何评估这个消费系统的容量回答采用容量规划三步法单线程压测找出一条消息的平均处理时间线性推算需要多少并发达到目标QPS实际峰值模拟用生产流量回放找到拐点同时设置水位告警当队列深度 阈值或消费延迟 5秒时报警六、总结这个消费模型具备生产级可靠性分区有序保证业务正确性、重试死信处理异常、背压机制防止下游被打垮。同时提供了一套完整的测试策略覆盖功能、并发、性能和混沌场景。更重要的是这个设计是可观测的——暴露了关键的metrics方便监控和容量规划。

相关文章:

模拟消息队列的消费逻辑-Java

分享一个大牛的人工智能教程。零基础!通俗易懂!风趣幽默!希望你也加入到人工智能的队伍中来!请轻击人工智能教程​​​​​https://www.captainai.net/troubleshooter 这是一个生产级消息队列消费逻辑模拟,重点突出&am…...

终极NVS别名系统详解:简化Node.js版本管理的5个实用技巧

终极NVS别名系统详解:简化Node.js版本管理的5个实用技巧 【免费下载链接】nvs Node Version Switcher - A cross-platform tool for switching between versions and forks of Node.js 项目地址: https://gitcode.com/gh_mirrors/nv/nvs Node Version Switch…...

PySpark数据处理:精准去重与排序

在数据处理过程中,如何高效地从大量记录中筛选出最新的信息,是每个数据工程师常遇到的问题。今天我们来探讨一个具体的例子,展示如何利用PySpark的窗口函数来实现数据的精准去重和排序。 问题背景 假设我们有一份数据表格,包含了用户ID、日期和访问网站的信息,表格如下:…...

破解工业数据孤岛:DB-GPT与OPC UA的智能融合方案

破解工业数据孤岛:DB-GPT与OPC UA的智能融合方案 【免费下载链接】DB-GPT open-source agentic AI data assistant for the next generation of AI Data products. 项目地址: https://gitcode.com/GitHub_Trending/db/DB-GPT 在工业4.0时代,数据…...

为什么92%的C#团队不敢在生产环境启用拦截器?——基于217家企业的AOP成熟度评估报告(含可执行检查清单)

更多请点击: https://intelliparadigm.com 第一章:C# 13 拦截器的工业级定位与认知误区 C# 13 引入的拦截器(Interceptors)并非传统意义上运行时动态织入的 AOP 工具,而是一种**编译期源码重写机制**,其核…...

从MSTAR到SARDet-100K:20个主流SAR数据集下载、标注格式与实战选型指南(2025版)

SAR目标检测数据集实战选型指南:从数据特性到工程落地(2025版) 当第一次打开HRSID数据集的标注文件时,我被COCO格式里密密麻麻的polygon坐标震撼了——这艘300像素长的货轮被精确勾勒出每一个船舷弧度。而隔壁实验室的博士却对着S…...

从USB到SATA:手把手拆解PCH芯片如何管理你的电脑外设(以Intel 400系列为例)

从USB到SATA:拆解Intel 400系列PCH芯片的外设管理架构 当你在电脑上插入U盘拷贝文件时,数据究竟经历了怎样的旅程?这个看似简单的操作背后,是Intel平台控制器中枢(PCH)在默默协调着USB控制器、SATA控制器和…...

libdxfrw实战指南:打破AutoCAD文件格式壁垒的C++解决方案

libdxfrw实战指南:打破AutoCAD文件格式壁垒的C解决方案 【免费下载链接】libdxfrw C library to read and write DXF/DWG files 项目地址: https://gitcode.com/gh_mirrors/li/libdxfrw 还在为CAD文件格式转换而头疼吗?libdxfrw作为一个强大的DXF…...

告别线程管理噩梦:ThreadPool项目中的工厂模式如何拯救你的C++程序

告别线程管理噩梦:ThreadPool项目中的工厂模式如何拯救你的C程序 【免费下载链接】ThreadPool A simple C11 Thread Pool implementation 项目地址: https://gitcode.com/gh_mirrors/th/ThreadPool 在C开发中,手动管理线程往往是一场噩梦——资源…...

LFM2.5-1.2B-Instruct商业应用:SaaS后台AI工单分类+优先级预测系统

LFM2.5-1.2B-Instruct商业应用:SaaS后台AI工单分类优先级预测系统 1. 轻量级AI模型在商业场景的价值 在当今企业服务领域,工单处理效率直接影响客户满意度和运营成本。传统工单系统依赖人工分类和优先级设定,不仅耗时耗力,还容易…...

Cursor Free VIP破解工具:如何免费解锁Cursor AI Pro功能的完整指南

Cursor Free VIP破解工具:如何免费解锁Cursor AI Pro功能的完整指南 【免费下载链接】cursor-free-vip [Support 0.45](Multi Language 多语言)自动注册 Cursor Ai ,自动重置机器ID , 免费升级使用Pro 功能: Youve rea…...

终极MiniDisc音乐管理指南:Platinum-MD让复古音乐焕发新生

终极MiniDisc音乐管理指南:Platinum-MD让复古音乐焕发新生 【免费下载链接】platinum-md Minidisc NetMD Conversion and Upload 项目地址: https://gitcode.com/gh_mirrors/pl/platinum-md 想要在2024年重新体验90年代的MiniDisc音乐魅力吗?Plat…...

实测GLM-TTS语音克隆:仅需3秒音频,还原度高达90%

实测GLM-TTS语音克隆:仅需3秒音频,还原度高达90% 最近,我花了一周时间深度体验了智谱开源的GLM-TTS语音克隆模型。说实话,结果有点超出我的预期。过去我也试过不少开源和商业的TTS方案,但像这样仅凭3秒音频就能把音色…...

《赛博朋克2077》DLSS优化档案

《赛博朋克2077》DLSS优化档案 【免费下载链接】dlss-swapper 项目地址: https://gitcode.com/GitHub_Trending/dl/dlss-swapper 原始版本:DLSS 2.3.0测试版本:DLSS 3.1.0测试日期:2024年3月15日硬件配置:RTX 4080 i7-13…...

蓝桥杯国赛程序复盘:NE555测频、PWM电机控制与PCF8591采集的联调避坑指南

蓝桥杯国赛实战复盘:多模块联调中的关键陷阱与优化策略 去年参加蓝桥杯国赛的经历让我深刻体会到,当NE555频率测量、PWM电机控制、PCF8591数据采集和超声波测距这些功能模块需要协同工作时,系统集成复杂度会呈指数级增长。官方文档和基础教程…...

保姆级教程:S32K3xx芯片上三种Secure Boot模式(BSB/ASB/SHE)到底怎么选?

S32K3xx芯片安全启动模式深度解析:BSB、ASB与SHE的黄金选择法则 在汽车电子和工业控制领域,安全启动(Secure Boot)已成为嵌入式系统设计的标配功能。NXP S32K3xx系列作为面向功能安全的车规级MCU,提供了三种不同的安全启动实现方案&#xff1…...

示波器实测:给按键并联0.1uF电容,硬件消抖效果到底有多明显?

示波器实测:0.1uF电容如何彻底驯服按键抖动? 每次按下机械按键时,你以为得到的是干净利落的电平跳变,实际上示波器会告诉你一个截然不同的故事——那些隐藏在毫秒级时间尺度下的电压毛刺,正是导致嵌入式系统误触发的元…...

别再死记硬背公式了!用Python代码实战拆解Diffusion中的两种引导技术(附避坑指南)

用Python实战拆解Diffusion模型中的两种引导技术:从代码理解原理到避坑指南 当你第一次看到"Classifier Guidance"和"Classifier-Free Guidance"这两个术语时,是否也被那些复杂的数学公式和理论推导搞得头晕目眩?作为一位…...

Cursor Pro破解工具完整解析:机器标识重置与永久免费解决方案

Cursor Pro破解工具完整解析:机器标识重置与永久免费解决方案 【免费下载链接】cursor-free-vip [Support 0.45](Multi Language 多语言)自动注册 Cursor Ai ,自动重置机器ID , 免费升级使用Pro 功能: Youve reached y…...

第17集:变更智能护航!用 AI 分析 Git PR 风险并自动生成回滚预案

第17集:变更智能护航!用 AI 分析 Git PR 风险并自动生成回滚预案 本集解锁内容:对接 GitLab Webhook 接收 Merge Request 事件、解析 K8s YAML / Nginx 配置 / SQL 等变更内容、用大模型自动评估风险等级、生成可执行回滚命令。学完本集,你能在面试中完整描述“AI 辅助变更…...

如何使用GPT-Repository-Loader:将代码仓库转换为LLM友好格式的完整指南

如何使用GPT-Repository-Loader:将代码仓库转换为LLM友好格式的完整指南 【免费下载链接】gpt-repository-loader Convert code repos into an LLM prompt-friendly format. Mostly built by GPT-4. 项目地址: https://gitcode.com/gh_mirrors/gp/gpt-repository-…...

5个简单步骤:使用Reset Windows Update Tool彻底解决Windows更新问题

5个简单步骤:使用Reset Windows Update Tool彻底解决Windows更新问题 【免费下载链接】Reset-Windows-Update-Tool Troubleshooting Tool with Windows Updates (Developed in Dev-C). 项目地址: https://gitcode.com/gh_mirrors/re/Reset-Windows-Update-Tool …...

告别ReLU?在PyTorch和TensorFlow中实战GELU激活函数,提升BERT模型微调效果

在PyTorch和TensorFlow中实战GELU激活函数:提升BERT微调效果的工程指南 当你在微调BERT模型时遇到训练不稳定、验证集表现波动大的问题,是否考虑过问题可能出在默认的ReLU激活函数上?GELU(Gaussian Error Linear Units&#xff09…...

从Siri到小米SU7:聊聊Azure Speech Studio背后的语音识别技术到底牛在哪

从Siri到小米SU7:揭秘Azure Speech Studio如何重塑语音交互体验 清晨,当你对着手机说出"小爱同学,今天天气怎么样"时,一段精密的AI交响乐正在幕后上演。从声波振动到文字转换,再到语义理解和动作执行&#x…...

AIGC工具平台-NotebookLM账号管理Cli应用

资料型 AI 工具常需要管理账号、项目、资料源和生成结果,用户希望在桌面端集中完成同步和操作。 NotebookLM 用于启动本地服务、维护账号状态、管理资料源和工作台生成,并通过操作日志确认执行结果。 文章目录 模块定位项目配置项目说明服务管理工作台操…...

水利工程师的Revit避坑指南:水闸BIM模型那些容易出错的细节(附族文件)

水利工程师的Revit避坑指南:水闸BIM模型那些容易出错的细节 在水利工程领域,BIM技术的应用已经从简单的三维展示发展到全生命周期的精细化管理。作为水利工程师,我们常常需要面对水闸这类复杂结构的建模挑战。不同于普通建筑,水闸…...

服务器端渲染SSR水合过程与客户端激活的技术实现细节

现代Web应用中,服务器端渲染(SSR)通过首屏直出提升用户体验,而水合(Hydration)与客户端激活(Client-side Activation)则是实现动态交互的关键技术。本文将深入解析SSR的核心技术细节…...

5分钟彻底修复Windows软件运行错误:VisualCppRedist AIO终极解决方案

5分钟彻底修复Windows软件运行错误:VisualCppRedist AIO终极解决方案 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经遇到过打开软件时突然…...

Visual C++ Redistributable AIO:一站式解决Windows运行库问题的终极指南

Visual C Redistributable AIO:一站式解决Windows运行库问题的终极指南 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist Visual C Redistributable AI…...

如何用AI守护你的健康?首个中医大语言模型仲景GPT完整指南

如何用AI守护你的健康?首个中医大语言模型仲景GPT完整指南 【免费下载链接】CMLM-ZhongJing 首个中医大语言模型——“仲景”。受古代中医学巨匠张仲景深邃智慧启迪,专为传统中医领域打造的预训练大语言模型。 The first-ever Traditional Chinese Medic…...