第九章 数据一致性与分布式事务

news/2026/1/22 21:44:59/文章来源:https://www.cnblogs.com/qxnm/p/19519098

第九章 数据一致性与分布式事务

在微服务架构中,数据一致性是最具挑战性的问题之一。当你把一个单体应用拆分成多个服务时,原本简单的数据库事务变成了复杂的分布式事务。这一章,我想分享一些实战经验,帮助你在这个"没有银弹"的领域做出明智的决策。

9.1 分布式事务的现实挑战

9.1.1 为什么传统ACID事务不再适用

还记得我第一次做微服务系统时,天真地以为可以用分布式事务协调器来解决所有问题。结果证明,这是一个巨大的错误。

传统2PC(两阶段提交)的问题

// ❌ 这就是问题所在 - 阻塞和资源锁定
public class DistributedOrderService
{public async Task CreateOrder(CreateOrderRequest request){using (var transaction = new TransactionScope(TransactionScopeOption.Required,new TransactionOptions { IsolationLevel = IsolationLevel.Serializable })){// 1. 扣减库存 - 锁定库存表await _inventoryService.DeductStock(request.Items);// 2. 创建订单 - 锁定订单表var order = await _orderRepository.CreateAsync(request);// 3. 处理支付 - 锁定账户表await _paymentService.ProcessPayment(order.TotalAmount);// 在所有操作完成之前,所有相关的表都被锁定// 其他请求必须等待,这就是性能问题的根源transaction.Complete();}}
}

2PC的问题不在于它不能工作,而在于它违背了微服务的核心原则:

  • 可用性牺牲:协调器故障会导致整个系统阻塞
  • 性能问题:资源锁定时间过长
  • 扩展性差:无法支持大规模分布式系统

9.1.2 接受最终一致性

在分布式系统中,我们需要接受一个现实:强一致性是有代价的。大多数情况下,最终一致性已经足够。

电商系统的最终一致性示例

// 订单创建流程 - 最终一致性版本
public class OrderApplicationService
{public async Task<CreateOrderResult> CreateOrder(CreateOrderCommand command){// 1. 本地事务:创建订单using var transaction = await _dbContext.Database.BeginTransactionAsync();try{var order = Order.Create(command.CustomerId, command.Items);await _orderRepository.AddAsync(order);await _dbContext.SaveChangesAsync();// 2. 发布领域事件(本地事务的一部分)await _eventPublisher.PublishAsync(new OrderCreatedEvent(order.Id,order.CustomerId,order.Items.Select(i => new OrderItemDto(i.ProductId, i.Quantity, i.Price)).ToList(),order.TotalPrice,DateTime.UtcNow));await transaction.CommitAsync();// 3. 返回成功,但此时库存可能还没扣减return CreateOrderResult.Success(order.Id);}catch (Exception ex){await transaction.RollbackAsync();return CreateOrderResult.Failure(ex.Message);}}
}// 库存服务监听订单创建事件
public class OrderCreatedEventHandler : IEventHandler<OrderCreatedEvent>
{public async Task HandleAsync(OrderCreatedEvent @event){try{// 1. 检查库存foreach (var item in @event.Items){var stockAvailable = await _inventoryRepository.CheckStockAsync(item.ProductId);if (stockAvailable < item.Quantity){// 库存不足,发布补偿事件await _eventBus.PublishAsync(new StockInsufficientEvent(@event.OrderId,item.ProductId,item.Quantity,stockAvailable));return;}}// 2. 预留库存var reservedItems = new Dictionary<Guid, int>();foreach (var item in @event.Items){await _inventoryService.ReserveStockAsync(item.ProductId, item.Quantity);reservedItems[item.ProductId] = item.Quantity;}// 3. 发布库存预留成功事件await _eventBus.PublishAsync(new StockReservedEvent(@event.OrderId,reservedItems,DateTime.UtcNow));}catch (Exception ex){_logger.LogError(ex, "Error handling OrderCreatedEvent for order {OrderId}", @event.OrderId);throw; // 重新抛出,让消息队列重试}}
}

9.2 Saga模式:分布式事务的实用方案

Saga模式是目前最实用的分布式事务解决方案。它将长事务分解为一系列本地事务,通过事件串联起来。

9.2.1 编排式Saga vs 协同式Saga

编排式Saga(Orchestration)

// 编排器 - 中央协调者
public class OrderProcessingSagaOrchestrator
{private readonly IOrderRepository _orderRepository;private readonly IInventoryServiceClient _inventoryService;private readonly IPaymentServiceClient _paymentService;private readonly IEventBus _eventBus;private readonly ILogger<OrderProcessingSagaOrchestrator> _logger;public async Task ProcessOrder(Guid orderId){var sagaState = await _sagaStateRepository.GetOrCreateAsync(orderId);try{switch (sagaState.CurrentStep){case OrderProcessingStep.OrderCreated:// 步骤1:预留库存var order = await _orderRepository.GetByIdAsync(orderId);var stockReserved = await _inventoryService.ReserveStockAsync(order.Items.Select(i => new StockReservationRequest(i.ProductId, i.Quantity)).ToList());if (!stockReserved){await CancelOrder(order, "Insufficient stock");return;}sagaState.MoveToStep(OrderProcessingStep.StockReserved);await _sagaStateRepository.SaveAsync(sagaState);// 继续下一步goto case OrderProcessingStep.StockReserved;case OrderProcessingStep.StockReserved:// 步骤2:处理支付var paymentResult = await _paymentService.ProcessPaymentAsync(orderId);if (!paymentResult.Success){await CompensateStockReservation(orderId);await CancelOrder(order, "Payment failed");return;}sagaState.MoveToStep(OrderProcessingStep.PaymentCompleted);await _sagaStateRepository.SaveAsync(sagaState);// 继续下一步goto case OrderProcessingStep.PaymentCompleted;case OrderProcessingStep.PaymentCompleted:// 步骤3:确认订单var orderToConfirm = await _orderRepository.GetByIdAsync(orderId);orderToConfirm.Confirm();await _orderRepository.UpdateAsync(orderToConfirm);sagaState.MoveToStep(OrderProcessingStep.Completed);await _sagaStateRepository.SaveAsync(sagaState);_logger.LogInformation("Order processing saga completed for order {OrderId}", orderId);break;}}catch (Exception ex){_logger.LogError(ex, "Error in order processing saga for order {OrderId}", orderId);await HandleSagaFailure(sagaState);}}private async Task CompensateStockReservation(Guid orderId){// 释放已预留的库存await _inventoryService.ReleaseStockAsync(orderId);_logger.LogInformation("Stock reservation compensated for order {OrderId}", orderId);}
}

协同式Saga(Choreography)

// 每个服务监听事件并决定下一步动作
public class PaymentService
{public async Task HandleStockReserved(StockReservedEvent @event){try{// 处理支付var paymentResult = await ProcessPayment(@event.OrderId, @event.TotalAmount);if (paymentResult.Success){// 支付成功,发布事件await _eventBus.PublishAsync(new PaymentCompletedEvent(@event.OrderId,paymentResult.TransactionId,DateTime.UtcNow));}else{// 支付失败,发布补偿事件await _eventBus.PublishAsync(new PaymentFailedEvent(@event.OrderId,paymentResult.ErrorMessage,DateTime.UtcNow));}}catch (Exception ex){_logger.LogError(ex, "Error processing payment for order {OrderId}", @event.OrderId);throw;}}
}public class OrderService
{public async Task HandlePaymentCompleted(PaymentCompletedEvent @event){try{// 确认订单var order = await _orderRepository.GetByIdAsync(@event.OrderId);order.Confirm();await _orderRepository.UpdateAsync(order);// 发布订单确认事件await _eventBus.PublishAsync(new OrderConfirmedEvent(@event.OrderId,@event.TransactionId,DateTime.UtcNow));}catch (Exception ex){_logger.LogError(ex, "Error confirming order {OrderId}", @event.OrderId);throw;}}public async Task HandlePaymentFailed(PaymentFailedEvent @event){try{// 取消订单var order = await _orderRepository.GetByIdAsync(@event.OrderId);order.Cancel(@event.ErrorMessage);await _orderRepository.UpdateAsync(order);_logger.LogWarning("Order {OrderId} cancelled due to payment failure: {Error}", @event.OrderId, @event.ErrorMessage);}catch (Exception ex){_logger.LogError(ex, "Error cancelling order {OrderId}", @event.OrderId);throw;}}
}

9.2.2 补偿事务的设计

补偿事务是Saga模式的核心,它需要仔细设计。

// 补偿事务接口
public interface ICompensatableAction
{Task ExecuteAsync();Task CompensateAsync();bool CanCompensate { get; }
}// 库存预留的补偿操作
public class ReserveStockAction : ICompensatableAction
{private readonly IInventoryService _inventoryService;private readonly Guid _orderId;private readonly Dictionary<Guid, int> _reservedItems;private bool _executed = false;public async Task ExecuteAsync(){foreach (var item in _reservedItems){await _inventoryService.ReserveStockAsync(item.Key, item.Value);}_executed = true;}public async Task CompensateAsync(){if (!_executed) return;foreach (var item in _reservedItems){await _inventoryService.ReleaseStockAsync(_orderId, item.Key, item.Value);}}public bool CanCompensate => _executed;
}// Saga步骤管理
public class SagaStep
{public string StepName { get; }public ICompensatableAction Action { get; }public bool IsCompleted { get; private set; }public bool IsCompensated { get; private set; }public async Task ExecuteAsync(){await Action.ExecuteAsync();IsCompleted = true;}public async Task CompensateAsync(){if (Action.CanCompensate && IsCompleted && !IsCompensated){await Action.CompensateAsync();IsCompensated = true;}}
}// Saga管理器
public class SagaManager
{private readonly List<SagaStep> _steps = new();private readonly ILogger<SagaManager> _logger;public void AddStep(string stepName, ICompensatableAction action){_steps.Add(new SagaStep(stepName, action));}public async Task<SagaExecutionResult> ExecuteAsync(){var completedSteps = new List<SagaStep>();try{foreach (var step in _steps){await step.ExecuteAsync();completedSteps.Add(step);_logger.LogInformation("Saga step completed: {StepName}", step.StepName);}return SagaExecutionResult.Success();}catch (Exception ex){_logger.LogError(ex, "Saga execution failed at step: {StepName}", completedSteps.LastOrDefault()?.StepName ?? "Unknown");// 补偿已完成的步骤(倒序)for (int i = completedSteps.Count - 1; i >= 0; i--){try{await completedSteps[i].CompensateAsync();_logger.LogInformation("Saga step compensated: {StepName}", completedSteps[i].StepName);}catch (Exception compensationEx){_logger.LogError(compensationEx, "Failed to compensate step: {StepName}", completedSteps[i].StepName);}}return SagaExecutionResult.Failure(ex.Message);}}
}

9.3 幂等性:分布式系统的守护神

在分布式系统中,幂等性是保证数据一致性的关键。

9.3.1 幂等性设计模式

// 幂等操作接口
public interface IdempotentOperation
{Guid OperationId { get; }DateTime CreatedAt { get; }
}// 幂等性处理器
public class IdempotencyHandler<T> where T : IdempotentOperation
{private readonly IDistributedCache _cache;private readonly ILogger<IdempotencyHandler<T>> _logger;public async Task<TResult> ExecuteAsync<TResult>(T operation, Func<Task<TResult>> operationFunc) where TResult : class{var cacheKey = $"idempotency:{typeof(T).Name}:{operation.OperationId}";// 检查是否已经执行过var cachedResult = await _cache.GetStringAsync(cacheKey);if (cachedResult != null){_logger.LogInformation("Operation {OperationId} already executed, returning cached result", operation.OperationId);return JsonSerializer.Deserialize<TResult>(cachedResult);}// 执行操作var result = await operationFunc();// 缓存结果var serializedResult = JsonSerializer.Serialize(result);await _cache.SetStringAsync(cacheKey, serializedResult, TimeSpan.FromHours(24));return result;}
}// 在API中使用幂等性
[ApiController]
public class OrdersController : ControllerBase
{private readonly IdempotencyHandler<CreateOrderOperation> _idempotencyHandler;[HttpPost]public async Task<ActionResult<OrderDto>> CreateOrder([FromHeader(Name = "Idempotency-Key")] string idempotencyKey,[FromBody] CreateOrderRequest request){if (string.IsNullOrEmpty(idempotencyKey)){return BadRequest("Idempotency-Key header is required");}var operation = new CreateOrderOperation{OperationId = Guid.Parse(idempotencyKey),Request = request,CreatedAt = DateTime.UtcNow};var result = await _idempotencyHandler.ExecuteAsync(operation,async () => await _orderService.CreateOrderAsync(request));return Ok(result);}
}

9.3.2 消息幂等性

// 消息去重处理器
public class MessageDeduplicationHandler
{private readonly IDistributedCache _cache;private readonly ILogger<MessageDeduplicationHandler> _logger;public async Task<bool> ProcessMessageAsync<T>(string messageId, Func<Task> messageHandler) where T : class{var cacheKey = $"message:{typeof(T).Name}:{messageId}";// 使用分布式锁确保并发安全var lockKey = $"lock:{cacheKey}";var lockId = Guid.NewGuid().ToString();try{// 尝试获取锁var lockAcquired = await _cache.SetStringAsync(lockKey, lockId, TimeSpan.FromSeconds(30), When.NotExists);if (!lockAcquired){_logger.LogWarning("Message {MessageId} is being processed by another instance", messageId);return false;}// 检查是否已经处理过var processed = await _cache.GetStringAsync(cacheKey);if (processed != null){_logger.LogInformation("Message {MessageId} already processed", messageId);return false;}// 处理消息await messageHandler();// 标记为已处理await _cache.SetStringAsync(cacheKey, "processed", TimeSpan.FromDays(7));return true;}finally{// 释放锁var currentLockId = await _cache.GetStringAsync(lockKey);if (currentLockId == lockId){await _cache.RemoveAsync(lockKey);}}}
}// 使用消息去重的事件处理器
public class IdempotentOrderCreatedHandler : IEventHandler<OrderCreatedEvent>
{private readonly MessageDeduplicationHandler _deduplicationHandler;private readonly IOrderService _orderService;public async Task HandleAsync(OrderCreatedEvent @event){var processed = await _deduplicationHandler.ProcessMessageAsync<OrderCreatedEvent>(@event.Id.ToString(),async () =>{// 实际的消息处理逻辑await _orderService.ProcessNewOrderAsync(@event);});if (!processed){_logger.LogInformation("OrderCreatedEvent {EventId} was not processed (duplicate)", @event.Id);}}
}

9.4 监控和追踪

在分布式系统中,监控和追踪是保证数据一致性的重要工具。

9.4.1 分布式追踪

// 使用OpenTelemetry进行分布式追踪
public class DistributedTracingConfiguration
{public static void ConfigureTracing(IServiceCollection services, IConfiguration configuration){services.AddOpenTelemetry().WithTracing(builder =>{builder.AddAspNetCoreInstrumentation().AddHttpClientInstrumentation().AddEntityFrameworkCoreInstrumentation().AddSource("OrderService", "PaymentService", "InventoryService").SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("ecommerce-system")).AddJaegerExporter(options =>{options.AgentHost = configuration["Jaeger:AgentHost"];options.AgentPort = int.Parse(configuration["Jaeger:AgentPort"]);});});}
}// 在业务代码中添加追踪
public class OrderService
{private readonly ActivitySource _activitySource;public async Task<Order> CreateOrderAsync(CreateOrderRequest request){using var activity = _activitySource.StartActivity("CreateOrder");activity?.SetTag("order.customer_id", request.CustomerId);activity?.SetTag("order.item_count", request.Items.Count);try{var order = Order.Create(request.CustomerId, request.Items);activity?.SetTag("order.id", order.Id);activity?.SetTag("order.total_amount", order.TotalPrice.Amount);await _orderRepository.AddAsync(order);return order;}catch (Exception ex){activity?.SetStatus(ActivityStatusCode.Error, ex.Message);activity?.RecordException(ex);throw;}}
}

9.4.2 一致性监控

// 一致性检查服务
public class ConsistencyMonitor
{private readonly IServiceProvider _serviceProvider;private readonly ILogger<ConsistencyMonitor> _logger;public async Task CheckOrderConsistencyAsync(){// 检查订单状态与支付状态的一致性var inconsistentOrders = await _orderRepository.FindInconsistentOrdersAsync();foreach (var order in inconsistentOrders){_logger.LogWarning("Inconsistent order found: {OrderId}, Status: {Status}, PaymentStatus: {PaymentStatus}",order.Id, order.Status, order.PaymentStatus);// 发送告警或自动修复await _alertingService.SendAlertAsync(new ConsistencyAlert{OrderId = order.Id,Issue = "Order status inconsistent with payment status",Severity = AlertSeverity.High});}}public async Task CheckInventoryConsistencyAsync(){// 检查库存数据的一致性var inconsistentProducts = await _inventoryRepository.FindInconsistentStockAsync();foreach (var product in inconsistentProducts){_logger.LogWarning("Inconsistent inventory found: {ProductId}, Available: {Available}, Total: {Total}",product.Id, product.AvailableQuantity, product.TotalQuantity);}}
}

9.5 小结

数据一致性是微服务架构中的永恒话题。记住几个关键原则:

  1. 接受最终一致性:强一致性是有代价的,大多数情况下最终一致性已经足够
  2. 设计幂等操作:幂等性是分布式系统的守护神
  3. 使用Saga模式:将长事务分解为可管理的步骤
  4. 监控和追踪:没有监控的分布式系统是不可维护的
  5. 自动化补偿:设计自动化的补偿机制,减少人工干预

最重要的是,数据一致性的解决方案没有标准答案。你需要根据业务需求、系统复杂度和团队能力来选择最适合的方案。

在下一章中,我们将探讨可观测性与监控,这是维护分布式系统健康运行的关键。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1201829.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第八章 微服务通信实现

第八章 微服务通信实现 微服务之间的通信是分布式系统中最具挑战性的部分。我见过太多团队因为通信设计不当而导致系统性能低下、故障频发。这一章,我想分享一些实战经验,帮助你设计高效可靠的微服务通信方案。 8.1 …

Java计算机毕设之基于springboot的民宿客房管理系统酒店客房管理系统设计(完整前后端代码+说明文档+LW,调试定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

autodl 上PaddleOCR-VL 部署(2026年1月22日亲测可用)

会话管理命令&#xff08;推荐使用 screen 或 tmux 后台运行&#xff09; 功能 screen 命令 tmux 命令 新建命名会话 screen -S 名字 tmux new -s 名字 列出所有会话 screen -ls tmux ls 重新连接会话 screen -r 名字 tmux attach -t 名字 detach&#xff08;后台运行&#xff…

【毕业设计】基于springboot的日报管理系统设计与实现(源码+文档+远程调试,全bao定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

欧洲百年品牌瀚德凯尔:专注座椅电梯,提升老年人生活质量

View Post欧洲百年品牌瀚德凯尔:专注座椅电梯,提升老年人生活质量瀚德凯尔是Savaria Group(萨瓦瑞亚集团)旗下品牌,专注于无障碍通行设备领域,品牌自1886年创立以来,始终专注于为老年人与行动不便人士提供安全、便…

Java毕设项目:基于springboot的民宿客房管理系统(源码+文档,讲解、调试运行,定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

第七章 服务拆分与边界定义

第七章 服务拆分与边界定义 服务拆分是微服务架构中最具挑战性的任务,也是最容易犯错的地方。我见过太多团队把微服务做成了"分布式单体",服务之间耦合严重,部署和运维复杂度急剧上升。这一章,我想分享一…

【计算机毕业设计案例】基于springboot的民宿房间预约管理系统设计与实现民宿客房管理系统(程序+文档+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

【毕业设计】基于springboot的民宿客房管理系统(源码+文档+远程调试,全bao定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

C++大模型SDK开发实录(三):流式交互协议SSE解析与httplib实现原理

目录 前言第一章&#xff1a;即时通信的基石——SSE协议解析1.1 为什么选择SSE&#xff1f;1.2 SSE数据格式 第二章&#xff1a;协议选型——SSE vs WebSocket2.1 轮询与WebSocket的局限2.2 技术特性对比 第三章&#xff1a;cpp-httplib的流式处理机制3.1 普通响应与流式响应的…

算法围猎下的App渠道归因如何去伪存真?

为什么你的精准广告&#xff0c;总能避开所有真客户&#xff1f; 这是一个让无数营销人深感挫败的“数字化悖论”。近日&#xff0c;行业资深观察者“老泡”的一篇深度述评引发了移动营销圈的强烈共鸣。文章指出&#xff0c;当品牌方沉溺于由算法编织的完美投流报表——百分百匹…

【课程设计/毕业设计】java基于springboot的民宿预约管理平台系统基于springboot的民宿客房管理系统【附源码、数据库、万字文档】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

我花6千块考下PMP一年后,聊聊它到底值不值

一、给想靠PMP涨薪的普通人&#xff1a;这3千值不值&#xff1f; 先上结论&#xff1a;别急着交钱&#xff0c;PMP对某些人是跳板&#xff0c;对另一些人可能就是“纸”。 去年我考下PMP&#xff0c;花了6K元&#xff08;培训2200考试费3900元&#xff09;&#xff0c;不算3个…

系统规划与管理师必看:2026年监控工具选型与实施指南

一、监控工具定义与核心内容 监控工具是用于实时采集、分析、展示和预警信息系统运行状态的技术手段&#xff0c;其核心目标是确保系统稳定性、性能达标及资源高效利用。在当今数字化快速发展的时代&#xff0c;信息系统已成为企业运营的核心支撑&#xff0c;一旦出现故障或性…

VL22 根据状态转移图达成时序电路

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

151. 反转字符串中的单词-day08

题目:151. 反转字符串中的单词 题目链接:https://leetcode.cn/problems/reverse-words-in-a-string/description/ 思路:1. 去除字符串的首尾空格,中间保留一个空格 2. 整个字符串全部反转 3. 根据空格,反转字符串…

学习进度 6

今天重点搞懂了昨天没明白的 Padding 和 Stride,Padding 就是在图像边缘补像素,防止卷积后特征图变小、边缘特征丢失,Stride 就是卷积核滑动的步长,步长设大一点特征图会更小,计算更快,试了下把步长从 1 改成 2,…

基于深度学习的苹果检测系统演示与介绍(YOLOv12/v11/v8/v5模型+Pyqt5界面+训练代码+数据集)

本文介绍了一套基于YOLO系列算法的苹果检测系统,该系统支持图片、视频和实时摄像头检测,具备多模型切换、结果可视化与统计等功能。系统采用Python3.10开发,前端使用PyQt5,数据库为SQLite,支持YOLOv5/v8/v11/v12等…

人群仿真软件:Pathfinder_(9).用户界面与工具栏详解

用户界面与工具栏详解 1. 用户界面概述 用户界面&#xff08;User Interface, UI&#xff09;是人群仿真软件Pathfinder的核心部分之一。它不仅提供了用户与软件交互的窗口&#xff0c;还决定了用户操作的便捷性和直观性。Pathfinder的用户界面主要由以下几个部分组成&#xff…

腾讯云的EdgeOne部署

blog 前端网站&#xff08;https://gzyblog.guoziyang.com&#xff09;已链接到 public 仓库 该项目使用 Github App 管理项目内容&#xff0c;请保管好后续创建的 Private key&#xff0c;不要上传到公开网上。 1. 克隆项目 开源项目地址&#xff1a;https://github.com/YYs…