[设计模式] Cola-StateMachine : 一个轻量实用的Java状态机框架

news/2024/11/17 3:07:34/文章来源:https://www.cnblogs.com/johnnyzen/p/18406389

1 概述:状态机

1.0 状态机 vs 工作流

  • 在介绍状态机之前,先介绍一个工作流(WorkFlow),初学者通常容易将两个概念混淆。
  • 工作流(WorkFlow),大体是指业务过程(整体或者部分)在计算机应用环境下的自动化,是对工作流程及其各操作步骤之间业务规则的描述。在计算机系统中,工作流属于计算机支持的协同工作(CSCW)的一部分。
  • 状态机工作流(WorkFlow)的一种类型,包括顺序工作流(Sequential)和状态机工作流(State Machine)。
  • 状态机有限状态自动机的简称,是现实事物运行规则抽象而成的一个数学模型
特性 状态机(State Machine) 工作流(WorkFlow)
关注点 单个任务 状态流转
循环 可以简单的实现循环 无循环
实现难度 比较麻烦,需要记录任务当前状态 实现简单
表达方式 表达更灵活 串行表达,不是很灵活
运行效率 低,可并行

1.1 定义

  • 状态机是一种描述系统行为的工具,通过定义一组状态状态转换规则,可以模拟和控制系统的状态变化

在软件工程中,状态机被广泛应用于实现系统的行为流程控制,特别是在处理业务流程游戏逻辑并发程序时。
状态机可以用于控制系统的不同状态,以及状态之间的转换条件和转换逻辑。

  • 内部状态流转 vs 外部状态流转
  • 外部转换会触发进入转换和退出转换,而内部转换则不会。
  • 外部转换是复合状态与其他状态之间发生的状态转换,内部转换是在复合状态内部的子状态之间发生的转换。
  • Cola StateMachine 状态机框架的定义
  • External Transition: 外部流转,表示当前状态与下一个状态不同
  • Internal Transition: 内部流转,表示状态不发生变化,只是触发了某个事件
/** 设置一个外部状态转义类型的builder,并设置from\to\on\when\perform*/
builder.externalTransition() //外部状态流转.from(OrderStatusEnum.INITIAL)//起始状态 : 初始化状态 // .fromAmong(States.STATE1, States.STATE2, States.STATE3) //起始状态 :有多个起始状态.to(OrderStatusEnum.PAY_PENDING)//目标状态 : 待支付 .on(OrderEventEnum.CREATE_ORDER)//触发事件 : 创建订单.when(createOrderHandler.condition()) //条件检查.perform(createOrderHandler.action()); //条件满足时的执行动作builder.internalTransition() //内部状态流转.within(OrderState.WAIT_PAYMENT) //等待支付.on(OrderStatusChangeEvent.PAYED) //事件 : 已支付.when(payedOrderHandler.condition()()).perform(payedOrderHandler.action()); //执行

1.2 状态机的组成

  • 一般的,状态机状态转移事件三个基本组成部分。
  • 状态是系统可能处于的不同情况
  • 转移定义了状态之间的关系和切换条件
  • 事件则是触发状态转换的因素。

通过定义状态转移,状态机能够将复杂系统的行为和状态分离,实现清晰的逻辑分离模块化

1.3 状态机的优点

  • 在实际应用中,状态机的使用可以提高代码的可读性可维护性,降低系统复杂度,方便对系统行为进行建模和控制。

同时,状态机的设计也可以帮助开发者更好地理解和组织系统流程简化开发过程

1.4 状态机的典型应用

  • 业务流程控制:状态机可以用于描述复杂的业务流程,将业务逻辑分解为一系列离散的状态和转换规则,使代码更加清晰、可维护和可扩展。例如,在电商系统中,订单状态机可以包含多种状态(已创建、已支付、已发货等),并定义了各个状态之间的转换规则和处理逻辑。

  • UI交互设计:状态机可以用于描述UI界面的各种状态和用户操作之间的关系,例如表单验证、导航菜单、游戏场景等,通过状态图来设计和呈现UI界面的交互逻辑,提高用户体验和操作效率。

  • 并发编程:状态机可以用于实现复杂的并发控制逻辑,例如多线程调度、协程管理等,通过状态和转移规则来控制不同任务之间的切换和执行顺序,提高程序的可伸缩性和性能。

1.5 状态机的选型

原始手搓版

  • 流程引擎易滥用,但状态机却实用且使用广泛,主要有以下两个原因:
  • 实现简单。最简单、轻量的状态机用一个 Enum 就能实现,基本是零成本。
  • 解耦、可阅读性高、可维护性高。使用状态机的 DSL 来表达状态的流转,语义会更加清晰,会增强代码的可读性和可维护性。

成熟框架

状态机的主要选型有3个:

  • Spring Statemachine
  • Squirrel statemachine

Spring StatemachineSquirrel statemachine优点:功能很完备
缺点也是功能很完备,使用起来比较复杂,并且是非线程安全

  • 在正常的中小型项目,其实是不需要用到那么多状态机的高级玩法。

如,状态的嵌套(substate),状态的并行(parallel,fork,join)、子状态机等等。
所以,这时候我们就需要一个轻量级高性能状态机框架。这就是我们今天的主角:Cola-StateMachine

  • Cola-StateMachine

https://github.com/alibaba/COLA/tree/master/cola-components/cola-component-statemachine

  • 阿里云团队开源的一款轻量级、高性能的状态机框架,用于解决业务流程状态流转的控制问题。
  • 它基于无状态化设计,支持事件驱动分布式事务,适用于构建复杂、且高并发状态机模型
  • 主要特点无状态、采用纯Java实现,使用Fluent Interface连贯接口)来定义状态和事件
  • 适用于管理状态转换的场景,如订单状态、支付状态等简单有限状态场景。
  • Cola-StateMachine可以帮助开发者方便地管理业务对象的状态转换,提高开发效率。

可以说,Cola-StateMachine 很适合在电商等项目场景的使用

  • 小结
状态机引擎 优点 缺点
Spring StateMachine 1. 强大的生命周期管理 2. 易于集成 3. 良好的文档和社区支持 1. 学习曲线较陡峭 2. 可能增加项目复杂性
Squirrel StateMachine 1. 轻量级 2. 简单易用 3. 性能高效 1. 功能相对有限
Cola-StateMachine 1. 高度可扩展 2. 语义清晰、可读性强 3. 线程安全 1. 文档和社区支持相对较少

2 Cola-StateMachine

2.1 核心概念

  • State:状态
  • Event:事件,状态由事件触发,引起变化
  • Transition:流转,表示从一个状态到另一个状态
  • External Transition:外部流转,两个不同状态之间的流转
  • Internal Transition:内部流转,同一个状态之间的流转
  • Condition:条件,表示是否允许到达某个状态
  • Action:动作,到达某个状态之后,可以做什么
  • StateMachine:状态机

2.2 状态流转模型的实现步骤

具体来说,Cola-StateMachine的流转模型可以通过以下步骤实现:

  • 定义状态:使用连贯接口定义系统的不同状态,每个状态可以通过类或接口来表示。
  • 定义事件:定义触发状态转换的事件,每个事件可以通过类或接口来表示。
  • 定义转移:根据业务规则定义状态之间的关系和转换条件。在Cola-StateMachine中,可以使用transition()方法来定义转移,指定起始状态、结束状态、事件和条件等参数。
  • 定义条件:使用condition()方法来定义是否允许到达某个状态。条件可以是一个布尔表达式或一个返回布尔值的函数。
  • 定义动作:在状态转换过程中,可以定义一些动作来执行特定的操作。使用action()方法来定义动作,指定一个执行特定操作的函数或Lambda表达式。
  • 创建状态机实例:根据定义的流转模型,创建Cola-StateMachine的实例。通过实例化状态机对象,可以控制系统的状态转换和行为。
  • 触发状态转换:通过调用状态机实例的方法来触发状态转换。根据事件的类型和条件,状态机会自动执行相应的动作并更新系统的状态。

通过以上步骤,Cola-StateMachine的流转模型可以帮助开发者实现清晰的状态转换逻辑和控制流程。

2.3 核心API

StateMachine

状态机接口定义

public interface StateMachine<S, E, C> extends Visitable{/*** Verify if an event {@code E} can be fired from current state {@code S}* @param sourceStateId* @param event* @return*/boolean verify(S sourceStateId,E event);/*** Send an event {@code E} to the state machine.** @param sourceState the source state* @param event the event to send* @param ctx the user defined context* @return the target state*/S fireEvent(S sourceState, E event, C ctx);/*** MachineId is the identifier for a State Machine* @return*/String getMachineId();/*** Use visitor pattern to display the structure of the state machine*/void showStateMachine();String generatePlantUML();
}
  • 首先,泛型机接口声明了3个泛型类,S表示状态类型,E表示事件类型,C表示上下文类型

  • 接口定义了以下方法:

  • verify(S sourceStateId, E event):验证当前状态是否可以接收指定事件,返回布尔值。该方法是状态机进行状态转换前的预处理过程,可以根据业务规则和当前状态来判断事件是否合法。
  • fireEvent(S sourceState, E event, C ctx):将指定事件发送给状态机,触发状态转换,并返回目标状态。该方法是状态机进行状态转换的核心逻辑,可以根据当前状态和事件来计算出目标状态,并执行相应的动作或逻辑。
  • getMachineId():获取状态机的唯一标识符。该方法可以用于区分不同的状态机实例,方便进行管理和监控。
  • showStateMachine():使用访问者模式展示状态机的结构。该方法可以将状态机的状态、事件、转移规则等信息以图形化形式展示出来,方便理解和调试。
  • generatePlantUML():生成PlantUML格式的状态机图。该方法可以将状态机的信息以PlantUML语言的形式输出,方便进行文档记录和分享。

2.3 Cola 状态机框架的3种流转模式

StateMachineBuilder<States, Events, Context> builder = StateMachineBuilderFactory.create();//external transitionbuilder.externalTransition().from(States.STATE1).to(States.STATE2).on(Events.EVENT1).when(checkCondition()).perform(doAction());//internal transitionbuilder.internalTransition().within(States.STATE2).on(Events.INTERNAL_EVENT).when(checkCondition()).perform(doAction());//external transitionsbuilder.externalTransitions().fromAmong(States.STATE1, States.STATE2, States.STATE3).to(States.STATE4).on(Events.EVENT4).when(checkCondition()).perform(doAction());builder.build(machineId);StateMachine<States, Events, Context> stateMachine = StateMachineFactory.get(machineId);stateMachine.showStateMachine();

2.4 Cola-StateMachine的集成与使用

以订单状态机为例,使用cola-statemachine实现一个状态机

step1 引入依赖

添加依赖,Spring Boot 项目依赖如下

<dependency><groupId>com.alibaba.cola</groupId><artifactId>cola-component-statemachine</artifactId><version>4.4.0</version>
</dependency>

step2 定义状态

创建一个枚举类来给我们的订单定义状态

@Getter
public enum OrderStatusEnum {INITIAL(0,"初始状态"),PAY_PENDING(1,"待支付"),PAY_FAILED(3,"支付失败"),PAY_SUCCESS(4,"已支付"),CANCELED("已取消"),;private int statusCode;private String statusDesc;OrderStatusEnum(int statusCode, String statusDesc) {this.statusCode = statusCode;this.statusDesc = statusDesc;}
}

step3 定义事件

同样的,我们用枚举来定义一个事件枚举类

/*** 订单事件枚举类*/
@Getter
public enum OrderEventEnum {CREATE_ORDER, // 创建订单PAYING,       //订单支付确认PAY_SUCCESS,  //订单支付成功PAY_FAIL      //支付失败;
}

step4 定义上下文

  • 状态机接口中有一个泛型C用来表示状态机的上下文信息,使用上下文信息,我们可以在状态转换过程中传递一些额外的数据和参数,方便进行状态机的状态转换和业务逻辑的处理。

上下文类可以帮我们传递参数,比如下面的上下文可以帮我们传递订单ID和金额

/*** 上下文信息类*/
@AllArgsConstructor
@NoArgsConstructor
@Data
public class OrderContext {/*** 订单ID*/private String orderId;/*** 订单金额*/private Integer payAmount;}

step5 定义状态机处理器

  • 在我们构造状态机的转移规则时,需要使用到两个方法:
  • 过滤条件方法 when(Condition condition)
  • 转换过程中要执行的动作 perform(Action<S, E, C> action);

这两个方法需要我们提供一个Condition conditionAction<S, E, C> action,为了方便管理和整洁,我们可以定义一个接口,然后定义两个方法提供这两个参数

下面,我就定义一个处理器接口,定义一个 condition() 方法用于返回条件对象, action() 用于我们执行的动作

状态机处理器接口如下:

StateMachineHandler

/*** 处理器接口,用于定义状态扭转的条件和执行的动作* @param <S>* @param <E>* @param <C>*/
public interface StateMachineHandler <S,E,C>{/*** 过滤条件* @return*/Condition<C> condition();/*** 执行动作* @return*/Action<S, E, C> action();}
  • condition():在状态机处理过程中,当某个事件发生并试图进行状态转移时,会先检查当前条件是否满足。条件通常根据上下文信息来决定是否允许状态转换。条件对象(Condition)表示在当前状态和事件下是否应该执行该处理器。
  • action(): 当状态转移被允许后,该动作将会被执行。动作(Action)通常定义了状态转移前后需要执行的操作,比如数据库更新、发送消息等。如果返回值为 null,则表示不需要执行任何操作。

Condition

Condition 是一个JDK自带的泛型接口,其中的类型参数 C 表示上下文类型。

public interface Condition<C> {/*** @param context context object* @return whether the context satisfied current condition*/boolean isSatisfied(C context);default String name(){return this.getClass().getSimpleName();}
}

Condition 接口定义了一个 isSatisfied() 方法,该方法接收一个上下文对象,并返回一个布尔值,表示该上下文对象是否满足当前条件,符合返回true

Action

Action 是一个泛型接口,其中的类型参数 S 表示状态类型,E 表示事件类型,C 表示上下文类型。

public interface Action<S, E, C> {public void execute(S from, S to, E event, C context);}
  • Action 接口定义了一个 execute() 方法,该方法接收起始状态 from、目标状态 to、触发事件 event 和上下文对象 context,用于执行相应的动作。

  • type(): 表示这个处理器的类型或标识。这可以用于区分不同的处理器,并在状态机配置中引用它们。

step6 创建 CreateOrderHandler : 由创始状态到待支付的创建订单事件处理器

我创建一个由创始状态到待支付的创建订单事件处理器

/*** 创建订单的处理器*/
@Component
public class CreateOrderHandler implements StateMachineHandler<OrderStatusEnum, OrderEventEnum, OrderContext> {@Overridepublic Condition<OrderContext> condition() {//进行条件判断,这里是通过上下文获取订单金额,订单金额大于0就符合条件return (context -> {return context.getPayAmount()>0;});}@Overridepublic Action<OrderStatusEnum, OrderEventEnum, OrderContext> action() {//执行逻辑操作return (from,to,event,context)->{ // 即 : CreateOrderAction//生成订单等操作,具体逻辑大家按实际情况实现};}
}
  • CreateOrderAction
public class CreateOrderAction implements Action<OrderStatusEnum, OrderEventEnum, OrderContext> {@Overridepublic void execute(OrderStatusEnum from, OrderStatusEnum to, OrderEventEnum event, OrderContext context) {// ...// 1.获取状态机StateMachine<OrderStatusEnum, OrderEventEnum, OrderContext> stateMachine = getStateMachine();// 2.组状态机 messageContextOrderContext orderContext = buildContext();// 3.状态机事件触发stateMachine.fireEvent(OrderStatusEnum.INIT, OrderEventEnum.CREATE_ORDER, orderContext);// ...}
}

step7 状态机配置,构建状态扭转规则

状态机配置,构建状态扭转规则

  • 配置不同状态下对不同事件的响应,也就是如何从一个状态转移到另一个状态

  • 我们通过在配置类中配置StateMachine来实现,下面是一个简单的StateMachine配置类,我只配置了创建订单的状态转换,还有其他状态转换,可以按照创建订单这个模式进行配置

@Slf4j
@Configuration
public class StateMachineConfig {/*** 状态机ID*/private static final String MACHINE_ID = "Order_StateMachine";@Autowiredprivate CreateOrderHandler createOrderHandler;/*** 状态机配置* @return*/@Beanpublic StateMachine<OrderStatusEnum,OrderEventEnum,OrderContext> stateMachine(){//创建 一个StateMachineBuilder 实例,用于构建和配置状态机StateMachineBuilder<OrderStatusEnum,OrderEventEnum,OrderContext> builder = StateMachineBuilderFactory.create();//创建订单事件/** 单个起始状态-外部状态流转 | 描述:订单起始状态为“初始化”,当发生“创建订单”事件执行状态转义,当满足 CheckCondition 时,执行 CreateOrderAction。 **/builder.externalTransition().from(OrderStatusEnum.INITIAL).to(OrderStatusEnum.PAY_PENDING).on(OrderEventEnum.CREATE_ORDER).when(createOrderHandler.condition()).perform(createOrderHandler.action());//创建状态机StateMachine<OrderStatusEnum, OrderEventEnum, OrderContext> build = builder.build(MACHINE_ID);return build;}}
  • 配置解析:
  • 通过 StateMachineBuilderFactory.create() 方法创建了一个 StateMachineBuilder 的实例,并使用泛型参数 <OrderStatusEnum,OrderEventEnum,OrderContext> 指定了状态、事件和上下文类型。
  • 使用 builder.externalTransition() 方法开始配置一个外部转移(external transition),表示在接收到特定事件时从一个状态转移到另一个状态。
  • 通过 .from(OrderStatusEnum.INITIAL) 指定了转移的起始状态为OrderStatusEnum.INITIAL
  • 有时候,可能会有多个起始状态,这就要使用fromAmong方法

例如.fromAmong(OrderStatusEnum.INITIAL,OrderStatusEnum.PAY_PENDING)

  • 通过 .to(OrderStatusEnum.PAY_PENDING) 指定了转移的目标状态为 OrderStatusEnum.PAY_PENDING。
  • 通过 .on(OrderEventEnum.CreateOrder) 指定了触发转移的事件为 OrderEventEnum.CreateOrder。
  • 通过 .when(createOrderHandler.condition()) 指定了执行该转移的条件。代码中使用createOrderHandler的 condition() 方法获取条件对象。
  • 通过 .perform(createOrderHandler.action()) 指定了转移时要执行的动作。使用 createOrderHandler的 action() 方法获取动作对象。

总结一下:from指定起始状态,to指定目标状态,on指定触发事件,when指定转移条件,perform指定状态转移时执行的动作

内部状态扭转

  • 除了外部状态流转,状态机还有一种内部状态流转

  • 内部状态流转是指当一个事件发生时,状态机并不切换到新的状态,而是在当前状态下执行一些操作或者更新内部状态,但保持在同一个状态内。

这种情况下,尽管状态看起来没有改变,但实际上可能进行了某种处理或者完成了某些业务逻辑。

  • 内部状态流转的配置如下
builder.internalTransition().within(OrderState.WAIT_PAYMENT).on(OrderStatusChangeEvent.PAYED).when(checkCondition()).perform(doAction());

可以看到内部流转没有目标状态,只有一个within的内部流转状态和一个on触发事件

上面例子的内部转换发生在WAIT_PAYMENT状态下,当发生PAYED事件时执行状态流转,当满足checkCondition()时,执行doAction操作,执行成功则返回状态WAIT_PAYMENT,即状态没有发生改变,只是执行了某些操作

step8 触发事件

  • 当我们触发一个事件、并想执行相应的状态转换时,就可以使用fireEvent方法进行操作
	//构造上下文对象OrderContext orderContext =  new OrderContext();;//根据状态机ID获取状态机StateMachine<OrderStatusEnum, OrderEventEnum, OrderContext> stateMachine =StateMachineFactory.get(MACHINE_ID);//将指定事件发送给状态机,第一个参数为当前状态,第二个参数为触发事件,第三个参数为上下文对象OrderStatusEnum resultOrderStatusEnum = stateMachine.fireEvent(OrderStatusEnum.INITIAL, OrderEventEnum.CreateOrder, orderContext);// 根据返回的目标状态进行相应操作if (resultOrderStatusEnum == OrderStatusEnum.PAY_PENDING) {// 状态转换成功后的其他业务逻辑处理} else {// 异常的状态转换处理逻辑}
  • StateMachine的fireEvent()方法用于触发状态机上的事件并执行相应的状态转换。这个方法通常接收三个参数:
  • sourceState: 当前的状态(源状态)。
  • event: 需要触发的事件。
  • context: 用户自定义的上下文对象,可能包含与当前状态或事件关联的数据。

X 参考文献

  • 状态(机)模式 - 博客园
  • Cola
  • https://github.com/alibaba/COLA/tree/master/cola-components/cola-component-statemachine
  • 实现一个状态机引擎,教你看清DSL的本质 - CSDN 【官方推文】
  • 走近“领域特定语言”(Domain-Specific Languages) - 博客园 【官方推文】
  • 状态机学习 - CSDN
  • 一个轻量实用的Java状态机框架--Cola-StateMachine - CSDN
  • UML 在线绘制

https://www.planttext.com/#google_vignette

  • 状态机的介绍和使用 - 博客园

基于 Cola

  • COLA中的cola-statemachine状态机理解与使用例 - CSDN

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

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

相关文章

Qml 实现瀑布流布局

最近在刷掘金的时候看到一篇关于瀑布流布局的文章,然鹅他们的实现都是前端的那套,就想着 Qml 有没有类似实现。 结果百度了一圈也没有( T_T Qml 凉了凉了 ),于是,我按照自己理解,简单实现了一个 Qml 版的瀑布流布局。【写在前面】 最近在刷掘金的时候看到一篇关于瀑布流布…

Rocky9

Rocky Linux 9.4 部署Zabbix 7.0 1-1.检测源 wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm #下载epel的源 rpm -ivh epel-release-latest-8.noarch.rpm #epel安装 rpm -Uvh https://repo.zabbix.com/zabbix/7.0/rocky/9/x86_64/zabbix-releas…

洛谷题单指南-常见优化技巧-P1714 切蛋糕

原题链接:https://www.luogu.com.cn/problem/P1714 题意解读:求长度不超过m的最大子段和 解题思路: 1、暴力法 设a[N]表示原数组,s[N]是a[N]的前缀和,对于每一个元素s[i],计算其与前m个元素之差,取差值最大值,用代码表示: for(int i = 1; i <= n; i++) {for(int j …

【专题】2024年中国折叠屏手机市场与消费趋势研究报告合集PDF分享(附原数据表

原文链接:https://tecdat.cn/?p=37645 中国智能手机市场目前仍处于整体增长瓶颈期,增长复苏未达预期,消费者换机预期周期不断延长,使得行业对破局点的探寻更为紧迫。与此同时,中端消费者购机呈现出消费降级与升级的分化态势,不过更多人会选择体验更好、配置更优的产品以…

Goby 漏洞发布|(CVE-2024-45195)Apache OFBiz /viewdatafile 代码执行漏洞【已复现】

漏洞名称:Apache OFBiz /viewdatafile 代码执行漏洞(CVE-2024-45195) English Name:Apache OFBiz /viewdatafile Code Execution Vulnerability(CVE-2024-45195) CVSS core: 8.0 漏洞描述: Apache OFBiz是一个开源企业资源规划(ERP)系统。它提供了一套企业应用程序,…

navicat无法连接远程的mysql--Host ‘xx.xx.xx.xx‘ is not allowed to connect to this MySQL server“

之前在远程虚拟机上面部署了mysql,想在本地客户端使用navicat连接数据库,结果提示:host xxx is not allowed to connect to this mysql server解决 出现这个提示,是由于我们使用root用户登录时,没有给root用户设置能访问的机器,所以我们设置一下,就可以了。1:登录mysql…

jQuery中开发插件

页面代码<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script s…

ubuntu 使用命令行查看硬件信息

ubuntu 使用命令行查看硬件信息 CPU cat /proc/cpuinfo其中,model name就显示了cpu的型号,cpu cores显示cpu的所有物理核心数量。 内存 cat /proc/meminfo其中,MemTotal就显示总内存大小,这里为32GB内存,SwapTotal显示了交换分区的内存大小,这里为 2GB。 硬盘大小 df -h可…

易百纳ss928开发板移植自训练模型跑通yolov5算法

ss928平台移植官方yolov5s算法参考文章:https://www.ebaina.com/articles/140000017418,这位大佬也开源了代码,gitee链接:https://gitee.com/apchy_ll/ss928_yolov5s 本文在参考上述文章的基础上,将官方yolov5s模型跑通,验证推理图片正确,然后移植自训练的推理模型,在移…

hyperworks软件许可优化解决方案

Hyperworks软件介绍 Altair 仿真驱动设计改变了产品开发,使工程师能够减少设计迭代和原型测试。提升科学计算能力扩大了应用分析的机会,使大型设计研究能够在限定的项目时间完成。现在,人工智能在工程领域的应用再次改变了产品开发。基于物理场的仿真驱动设计与机器学习相结…

Xcode 16 RC (16A242) 发布下载,正式版下周公布

Xcode 16 RC (16A242) 发布下载,正式版下周公布Xcode 16 RC (16A242) - Apple 平台 IDE IDE for iOS/iPadOS/macOS/watchOS/tvOS/visonOS 请访问原文链接:https://sysin.org/blog/apple-xcode-16/,查看最新版。原创作品,转载请保留出处。 作者主页:sysin.orgXcode 16 的新…

md5拓展攻击

md5拓展攻击 【工具】hash-ext-attack/img/img_1.png at master shellfeel/hash-ext-attack GitHub 【攻击方法例题】https://ctf.org.cn/2019/11/19/哈希长度扩展攻击以及HashPump安装使用和两道题目/ 实际中的利用条件如下:基于哈希的消息认证码 (MAC):长度扩展攻击的关键…