camunda入门教程及实现原理

news2024/11/26 16:40:35

1、camunda简介

1、介绍:
Camunda是一种工作流引擎。
Camunda BPM 是一个轻量级、开源灵活的工作流框架,是由Java开发的一个纯Java库。它的核心是一个在Java虚拟机内部运行的原生BPMN 2.0流程引擎,因此它可以嵌入到任何Java应用程序或运行时容器中。
官方文档:https://docs.camunda.org

 源码地址:https://github.com/camunda

2、原理
动态探针:动态探针是应用程序没有定义,在程序运行时动态添加的探针。动态探针类似于异常处理机制,当系统产生一个异常,就会跳转去执行对应的 handle。

    动态探针会在函数入口和出口插入一些断点,程序执行到断点时候会去执行对应的 handle,从而达到观测应用程序的目的。这里的中断是指 trap(陷阱),在X86体系是int3指令。
     Camunda采用动态探针技术实现的动态追踪。用于监视生产系统中的事件。记录特定事件,跟踪问题等。

2、快速构建camunda demo项目

  地址:https://start.camunda.com/

在这里插入图片描述
上面可选的版本比较新,如果项目中springBoot版本比较老可以参照:camunda版本和springBoot版本对照

下载之后自行把数据库连接信息改成mysql即可,然后第一次启动会生成camunda相关的表(49个)如下:
在这里插入图片描述
ACT_RE_:RE代表存repository。带有此前缀的表包含“静态”信息,例如流程定义和流程资源(图像、规则等)。
ACT_RU_
:RU代表runtime。这些是运行时表,包含流程实例、用户任务、变量、作业等的运行时数据。引擎仅在流程实例执行期间存储运行时数据,并在流程实例结束时删除记录。这使运行时表既小又快。
ACT_ID_:ID代表identity。这些表包含身份信息,例如用户、组等。
ACT_HI_
:HI代表history。这些是包含历史数据的表,例如过去的流程实例、变量、任务等。
ACT_GE_*:GE代表 general一般数据,用于各种用例。

3、camunda模型BPMN、DMN、FROM介绍

  camundaBPM和modeler历史版本下载:https://downloads.camunda.cloud/release/

  camunda官方文档介绍:https://docs.camunda.org/manual/7.16/reference/bpmn20/

camunda模型BPMN、DMN、FROM介绍(中文)。

  **流程图样例:**

在这里插入图片描述
流程的开启方式:
1、在camunda管理系统中点startProcess开启。
在这里插入图片描述
2、用postMan调开启流程接口(post请求)。
在这里插入图片描述
3、自定义接口,然后在接口中调用RuntimeService的开启流程方法。
在这里插入图片描述

4、Servcie Task - 调用外部服务

4.1 调用Java代码 - 实现JavaDelegate
Java Class - 指定代理类全路径(实现接口JavaDelegate、ActivityBehavior,抛异常则回滚到上一步),如:com.example.workflow.delegate.MyDelegate
Delegate Expression - 使用表达式来提取代理对象(实现接口JavaDelegate、ActivityBehavior),更适合SpringBoot环境,如: m y D e l e g a t e B e a n E x p r e s s i o n − 调 用 方 法 表 达 式 , 如 : {myDelegateBean} Expression - 调用方法表达式,如: myDelegateBeanExpression{myBean.doWork()}
Expression - 解析值表达式(Evaluating a value expression)
在这里插入图片描述
在这里插入图片描述
4.2 External (External Task)
指定task对应的topic
由外部Worker通过REST API(Long Polling)主动获取并锁定(可指定超时时间)任务(亦支持Java API)
外部worker通知流程 完成Complete 或 失败Failure
在这里插入图片描述
SpringBoot ExternalTaskHandler示例代码:

@ExternalTaskSubscription(topicName = "payment-biz")
@Bean
public ExternalTaskHandler paymentBizHandler() {
    return (externalTask, externalTaskService) -> {
        //获取流程变量
        String productName = externalTask.getVariable(PRODUCT_NAME);
        Double productPrice = externalTask.getVariable(PRODUCT_PRICE);
        String paymentAssignee = externalTask.getVariable(PAYMENT_ASSIGNEE);
        Double productDiscountPrice = externalTask.getVariable(PRODUCT_DISCOUNT_PRICE);
        log.info("The External Task {} has been checked!", externalTask.getId());
        //完成任务
        externalTaskService.complete(externalTask);
        //完成任务且添加流程变量
        //externalTaskService.complete(externalTask, Variables.putValueTyped("creditScores", creditScoresObject));
        log.info("Payment SUCCESS - paymentAssignee={}, productName={}, productPrice={}, productDiscountPrice={}",
                paymentAssignee,
                productName,
                productPrice,
                productDiscountPrice);
 
        //任务失败
        //externalTaskService.handleFailure(
        //        externalTask,
        //        "errorMsg",
        //        "errorDetails",
        //        1,
        //        10L * 60L * 1000L);
 
    };
}

4.3 调用web服务(REST、SOAP)
关于使用connector的细节可参见:
https://docs.camunda.org/manual/latest/user-guide/process-engine/connectors
https://github.com/camunda/camunda-bpm-examples/tree/master/servicetask
在这里插入图片描述

5、Business Rule Task - 业务规则任务(可绑定DMN)

 如下图可通过Business Rule Task绑定单独的DMN文件中的Decision决策表格,
  以此实现根据不同输入产生不同输出的效果,
  DMN输出结果需通过Result Variable等设置进行映射,
  映射之后才可供后续流程元素进行访问。

在这里插入图片描述
例如如上图中的Decision Ref中product-discount-rule即对应DMN模型中的Desition.id。
如下即为具体决策表格内容
在这里插入图片描述

6、会签流程介绍。

  会签: 在流程业务管理中,任务是通常都是由一个人去处理的,而多个人同时处理一个任务,这种任务我们称之为会签任务。

6.1、按照会签执行的顺序分为:
a)串行会签:串行会签也叫顺序会签,指按照提交流程处理人的次序user1、user2、user3依次接收待办任务,并按顺序处理流程。

  b) 并行会签:指user1、user2、user3同时接收到流程待办任务,并行处理。

在这里插入图片描述
6.2、按照会签通过的比例分为:
a) 全部通过:会签人全部审批通过表决后,会签通过。

  b) 按数量通过:达到一定数量的通过表决后,会签通过。

  c) 按比例通过:达到一定比例的通过表决后,会签通过。

  d) 一票通过:只要有一个表决通过的,会签通过。

  e) 一票否决:只要有一个表决时否定的,会签通过。

6.3 会签参数设置
主要参数配置说明:

     1、 loop cardinality:循环基数。可选项。可以直接填整数,表示会签的人数。
     2、 Collection:集合。可选项。会签人数的集合,通常为list,和loop cardinality二选一。
     3、 Element variable:元素变量。选择Collection时必选,为collection集合每次遍历的元素。
     4、 Completion condition:完成条件。可选。比如设置一个人完成后会签结束,那么其他人的代办任务都会消失。

在这里插入图片描述
6.4 配置会签流程处理人
需要注意的是,右侧的Assignee,Candidate Users,Candidate Groups,分别表示按照负责人/候选用户/候选组。

  采用Assignee,填写上一步中的Element Variable字段的内容,即可获取当前审批人,注意是动态变量,${}格式,即会签人Collection中遍历的每一个人赋值给该变量。

在这里插入图片描述
6.5 其它说明
1、为并行节点设置 Completion Condition 条件为 ${nrOfCompletedInstances == 1},是实现或签的方法。
2、参考上述代码,设置变量 .setVariable(“assignee”,“新加签的用户”),可以为并行会签节点进行加签。
3、为并行节点设置 Completion Condition 属性,条件设置为 ${nrOfPassInstances / nrOfInstances > 0.5},是实现会签比例大于 50% 自动通过的方法(其中 nrOfPassInstances 不是 camunda 内置变量,是通过 complete 监听器自己维护的一个变量,节点每个实例完成后如果是同意则 nrOfPassInstances 加1)。

7、camunda核心对象ProcessEngine

7.1 ProcessEngine初始化
ProcessEngine是Camunda流程引擎的核心。我们在流程中的很多具体的处理比如流程部署、流程部署、流程审批等操作都是通过XXXService来处理的。而相关的XXXService都是通过ProcessEngine来管理的。

       在SpringBoot项目会根据我们导入的依赖完成自动装配,从而完成ProcessEngine的自动注入。

在这里插入图片描述
7.2 从ProcessEngine中,你可以获得包含工作流/BPM方法的各种服务

在这里插入图片描述

服务名称介绍
运行时服务-RuntimeService首先可以通过一个流程定义启动多个流程实例。也能用于处理检索和存储流程变量的服务
过滤器服务-FilterService允许创建和管理过滤器。过滤器是像任务查询一样的存储查询。例如,过滤器被任务列表用来过滤用户任务
身份服务-IdentityService是非常简单的。它允许对组和用户进行管理(创建、更新、删除、查询…)。重要的是要理解,核心引擎实际上在运行时并不对用户进行任何检查
表单服务-FormService一个可选的服务。提供了表单功能
管理服务-ManagementService它允许检索关于数据库表和表元数据的信息。此外,它暴露了查询功能和Job的管理操作。Job在引擎中被用于各种事情,如定时器、异步延续、延迟暂停/激活等。
案例服务-CaseService与运行时服务(RuntimeService)类似,但用于案例实例。它处理启动案例定义的新案例实例并管理案例执行的生命周期。该服务也被用来检索和更新案例实例的流程变量。
外部任务服务-ExternalTaskService提供对外部任务实例的访问。外部任务代表在外部处理的工作项目,独立于流程引擎。
历史服务-HistoryService暴露了引擎收集的所有历史数据。当执行流程时,引擎可以保留很多数据(这是可配置的),如流程实例的开始时间、谁做了哪些任务、完成任务花了多长时间、每个流程实例遵循的路径等。该服务主要暴露了访问这些数据的查询功能。
决策服务-DecisionService允许评估部署在引擎中的决策。它是评估独立于流程定义的业务规则任务中的决策的一种选择。
任务服务-TaskService围绕用户审批操作的一切都会被归纳到TaskService。比如:查询分配给用户或组的任务,创建新的独立任务。这些是与流程实例无关的任务,操纵一个任务被分配给哪个用户,或者哪个用户以某种方式参与到任务中,声称并完成一项任务。声称意味着有人决定成为该任务的受让人,意味着这个用户将完成该任务。完成意味着 “完成任务的工作”等
仓库服务RepositoryService提供了管理和操纵部署和流程定义的操作

7.3 RuntimeService介绍
常用操作:

可根据不同API启动实例,并返回ProcessInstance对象;
可异步删除所有实例,并返回Batch对象;
可获取变量信息,并返回VariableMap对象;
可获取变量信息,并返回Map<String, Object>对象;
可获取单个变量信息,并返回TypedValue;
可查询执行实例,并返回ExecutionQuery对象;
可自定义SQL查询并执行实例,并返回NativeExecutionQuery对象;
可查询流程实例信息,并返回ProcessInstanceQuery对象;
可自定义SQL查询流程实例信息,并返回NativeProcessInstanceQuery对象;
可查询Incident相关信息,并返回Incident对象;
开启流程示例:
在这里插入图片描述
从任意节点启动实例:

@Test
public void createProcessInstanceByKey() {
    String processInstanceByKey = "leave";
    String activityId = "Activity_1r8r4jn";
 
    ProcessInstantiationBuilder processInstantiationBuilder = runtimeService.createProcessInstanceByKey(processInstanceByKey);
    ProcessInstance processInstance = processInstantiationBuilder.businessKey("001")
            //某节点之前开始
            .startBeforeActivity(activityId)
            .execute();
    System.out.println(processInstance.getId() + "," + processInstance.getBusinessKey() + "," + processInstance.getProcessDefinitionId());
 
}
 
 
@Test
public void createProcessInstanceByKey2() {
    String processInstanceByKey = "leave";
    String activityId = "Flow_1c279og";
 
    ProcessInstantiationBuilder processInstantiationBuilder = runtimeService.createProcessInstanceByKey(processInstanceByKey);
    ProcessInstance processInstance = processInstantiationBuilder.businessKey("001")
            //从连线开始触发
            .startTransition(activityId)
            .execute();
    System.out.println(processInstance.getId() + "," + processInstance.getBusinessKey() + "," + processInstance.getProcessDefinitionId());
 
}
 
 
@Test
public void createProcessInstanceByKey3() {
    String processInstanceByKey = "leave";
    String activityId = "Activity_0zafxq7";
 
    ProcessInstantiationBuilder processInstantiationBuilder = runtimeService.createProcessInstanceByKey(processInstanceByKey);
    ProcessInstance processInstance = processInstantiationBuilder.businessKey("001")
            //某节点之后
            .startAfterActivity(activityId)
            .execute();
    System.out.println(processInstance.getId() + "," + processInstance.getBusinessKey() + "," + processInstance.getProcessDefinitionId());
 
}
 
@Test
public void createProcessInstanceByKey4() {
    String processInstanceByKey = "leave";
    String activityId = "Activity_0zafxq7";
 
    //跳过监听器
    boolean skipCustomListeners = true;
    boolean skipIoMappings = true;
 
    ProcessInstantiationBuilder processInstantiationBuilder = runtimeService.createProcessInstanceByKey(processInstanceByKey);
    ProcessInstance processInstance = processInstantiationBuilder.businessKey("001")
            .startAfterActivity(activityId)
            .execute(skipCustomListeners, skipIoMappings);
    System.out.println(processInstance.getId() + "," + processInstance.getBusinessKey() + "," + processInstance.getProcessDefinitionId());
 
}

当流程实例启动时,以下两张表会有新的数据插入:

  ACT_RU_EXECUTION (正在执行对象表)
  ACT_RU_TASK (正在执行任务表)

  同时会有几张历史表也会插入数据(ACT_HI_XXXX都是历史表):

  ACT_HI_ACTINST
  ACT_HI_TASKINST
  ACT_HI_PROCINST (历史流程实例表与运行实例一对一)
  ACT_HI_IDENTITYLINK

  **驳回到某个节点示例:**
ActivityInstance tree = runtimeService.getActivityInstance(processInstanceId);
       List<HistoricActivityInstance> resultList = historyService
               .createHistoricActivityInstanceQuery()
               .processInstanceId(processInstanceId)
               .activityType("userTask")
               .finished()
               .orderByHistoricActivityInstanceEndTime()
               .asc()
               .list();
       //得到任务节点id
       List<HistoricActivityInstance> historicActivityInstanceList = resultList.stream().filter(historicActivityInstance -> historicActivityInstance.getActivityId().equals(rejectTaskDTO.getTaskKey())).collect(Collectors.toList());
       HistoricActivityInstance historicActivityInstance = historicActivityInstanceList.get(0);
       String toActId = historicActivityInstance.getActivityId();
       taskService.createComment(task.getId(), processInstanceId, rejectTaskDTO.getMessage());
       runtimeService.createProcessInstanceModification(processInstanceId)
               .cancelActivityInstance(getInstanceIdForActivity(tree, task.getTaskDefinitionKey()))
               .cancelAllForActivity(currentTaskId)
               .setAnnotation("进行了驳回到指定任务节点操作")
               .startBeforeActivity(toActId)//启动目标活动节点
               .execute();

获取正在运行的实例节点:

/**
 * select * from ACT_RU_EXECUTION where PROC_INST_ID_ = ?
 */
@Test
public void getActiveActivityIds() {
    //执行实例ID
    String executionId = "6001";
    List<String> activeActivityIds = runtimeService.getActiveActivityIds(executionId);
    System.out.println("####" + activeActivityIds);
}
 
 
@Test
public void getActivityInstance() {
    //执行实例ID
    String processInstanceId = "6001";
    ActivityInstance activityInstance = runtimeService.getActivityInstance(processInstanceId);
    System.out.println(activityInstance);
}

7.4 TaskService介绍
一个实例启动过后,对应的任务需要完成才会走入下一个节点,这时候我们会有大量对Task的操作,从产品的角度来看,一个任务启动会根据规则分配到人,然后该用户获取自己的任务列表,进行操作后完成该任务。

以下是任务常用方法及说明:

/**
 * 通过受理人查询任务
 */
public List<Task> getTasksByAssignee(String assignee, int first, int max) {
    return taskService.createTaskQuery().taskAssignee(assignee).listPage(first, max);
}
/**
 * 通过流程id查询任务
 */
public List<Task> getTasksByProcessInstanceId(String processInstanceId, int first, int max) {
    return taskService.createTaskQuery().processInstanceId(processInstanceId).listPage(first, max);
}
/**
 * 完成任务
 */
public void completeTask(String taskId) {
    taskService.complete(taskId);
}
/**
 * 通过任务id设置变量
 */
public void setVariByTaskId(String taskId,Map<String,Object> variMap) {
    taskService.setVariables(taskId,variMap);
}
/**
 * 通过任务id查询
 */
public Task getTaskById(String taskId) {
    return taskService.createTaskQuery().taskId(taskId).singleResult();
}

任务相关表:

ACT_HI_TASKINST
ACT_HI_IDENTITYLINK
ACT_HI_ACTINST
ACT_RU_TASK

8、camunda监听器

8.1 执行监听器
执行监听器的触发事件有:start、end、take;其中节点有start、end两种事件,而连线则有take事件。

  如下给或签节点设置了开始事件和结束事件的执行监听器:        

在这里插入图片描述
开启一条流程实例测试一下,这里我们在发起流程时就把所有节点审批人参数设置好。

在这里插入图片描述
发起人节点调用审批通过后就触发或签节点的执行监听器开始事件,两次是因为该监听事件是设置在节点上的,而或签节点设置了两个处理人,所以它会创建两个待办任务,每个待办任务都有对应的执行器,等到或签节点有人审批通过了,就会触发执行监听器结束事件。

在这里插入图片描述
说明:在触发该监听器之前,流程引擎就需要知道该节点上有几个待办任务从而创建对应数量的执行器。所以你可以选择在节点上的执行监听器结束事件触发时去设置下一节点审批人

8.2 任务监听器
任务监听器的触发事件有:create, assignment, update, complete, delete or timeout。

  这里我们演示常用的create、assignment、complete事件。

在这里插入图片描述
重新部署后,把审批人设置方式再改回到发起流程时设置,然后发起流程实例,这里如果执行监听器的触发在任务监听器之前,那就更不能在任务监听器上动态设置审批人了。

在这里插入图片描述
所以动态设置审批人的条件就是要在节点执行监听器的开始事件触发之前就设置好审批人参数。

总结:
在这里插入图片描述

9、问题总结。

  1、springBoot版本和camunda版本不一致问题。

  2、流程开启后需要记录流程id,然后再通过流程id+用户查询任务并完成任务。

  3、用户任务节点的审批人必须在该节点之前设置好。

  4、使用runtimeservice开启流程时会造成线程阻塞,直到用户节点或结束节点。所以这里在实际使用时看是否需要异步。

  5、如果发生异常,回滚到上一节点,如何查看该流程卡在哪个节点上。

10、问题探讨。

  1、数据库表如何分离,camunda的49张表和业务表如何分开?

  2、任务表、用户、用户组、租户等这些表如何用?是自己实现还是直接用camunda的?

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

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

相关文章

Linux 添加环境变量的两种方法 exprot 临时法 vi /etc/profile永久法

编写一个shell脚本之后&#xff0c;怎么可在任意目录运行改脚本呢&#xff1f;为什么别人写的脚本可以直接运行&#xff0c;自己写的脚本就会出现 -bash: XXXXX.sh: command not found 这样的错误呢&#xff1f; 1、举例验证&#xff0c;先新建一个HelloWorld的shell脚本&…

Alibaba 工具型技术系列,实战技术针对于项目中常用的 Excel 操作指南

ExcelIgnoreUnannotated 默认不加 ExcelProperty 的注解的都会参与读写&#xff0c;加了不会参与 通用参数 ReadWorkbook,ReadSheet 都会有的参数&#xff0c;如果为空&#xff0c;默认使用上级。 converter 转换器&#xff0c;默认加载了很多转换器。也可以自定义。 rea…

emlog模板开发基础2022最新指南

emlog模板的开发基础指南,如果想要开发emlog的模板,你必须知道那些开发内容呢&#xff1f;下面将介绍分析emlog5下的模板基本结构以及基本变量、函数的作用。 首先我们用该知道emlog的模板是位于根目录content\templates\文件夹下,每个模板都是一个单独的文件夹,文件夹以模板名…

[附源码]JAVA毕业设计-英杰学堂网上教学平台-(系统+LW)

[附源码]JAVA毕业设计-英杰学堂网上教学平台-&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项…

一道关于Vue的数据绑定和依赖收集的面试题

概要 分享一道Vue的面试题&#xff0c;该题涉及Vue的响应式数据绑定和依赖收集&#xff0c;希望可以加深大家对Vue原理的理解。 题面 有如下html和JS&#xff0c;要求使用Vue的响应式数据原理和依赖收集原理&#xff0c;实现createApps和ref方法。只能使用原生JS&#xff0c…

教育的本质——采用不同学习方式,学习者在两周后还能记住的内容有多少

目录 一、学习金字塔模型 二、学习曲线 三、左右脑交替学习法 一、学习金字塔模型 “学习金字塔模型”&#xff0c;人们学习的效率一共分为七个层次&#xff1a; 第一层 ~ 第四层&#xff1a;这是我们最熟悉不过的形式&#xff0c;在学生时代&#xff0c;老师在上面讲课、…

【Leetcode】225. 用队列实现栈、232. 用栈实现队列

作者&#xff1a;一个喜欢猫咪的的程序员 专栏&#xff1a;《Leetcode》 喜欢的话&#xff1a;世间因为少年的挺身而出&#xff0c;而更加瑰丽。 ——《人民日报》 目录 225. 用队列实现栈 232. 用栈实现队列 225. 用队列实现栈 225. 用队…

91-143-Scala-集合模式泛型等

91-Scala-集合模式泛型等&#xff1a; Scala 的集合有三大类&#xff1a;序列 Seq、集 Set、映射 Map&#xff0c;所有的集合都扩展自 Iterable特质。 2&#xff09;对于几乎所有的集合类&#xff0c;Scala 都同时提供了可变和不可变的版本&#xff0c;分别位于以下两个包 不…

人工智能(AI)背后人工的力量——数据标注

尽管随着AI的普及&#xff0c;我们在生活中越来越依赖于人工智能&#xff0c;但“人工智障”的相关调侃也从来没有消失过。 相信大家都知道&#xff0c;如果我们想要让AI准确识别出图中的鸟&#xff0c;我们需要在数据集中手动将这些照片标记为鸟&#xff0c;然后让算法和图像…

c3p0数据库连接池的使用

c3p0数据库连接池的使用 c3p0的官网&#xff1a;c3p0 - JDBC3 c3p0数据库连接池有两种方法 导入jar包 首先两种方法都需要导入jar包 图中打钩的&#xff0c;第一个是c3p0的包&#xff0c;第二个是连接数据库的 在WEB-INF下新建lib包&#xff0c;将所需要的jar导入 右键添加…

【Java技术专题】「OpenJDK专题」想不想编译属于你自己的JDK呢?(Windows环境)

Win10下编译OpenJDK8 编译环境 Windows10专业版64位&#xff1b; 编译前准备 Tip&#xff1a; 以下软件的安装和解压目录尽量不要包含中文或空格&#xff0c;不然可能会出现问题 安装 Visual Studio 2010 Professional 在windows下编译JDK需要使用Visual Studio 2010 Profes…

反抗与反噬:亚马逊被迫结束封号神秘主义,不再粗暴关店

“每一天醒来&#xff0c;都要看一眼自己的店铺是否还在。”、“账号被封之后&#xff0c;自己也曾第一时间向平台申诉&#xff0c;经历过一次、两次甚至是多次申诉无果后&#xff0c;才意识到账号是真的回不来了。”、“过去传言大卖有保护伞&#xff0c;这一回才发现做亚马逊…

B站有哪些值得Java初学者看的视频,Java学习路线

我的读者中有很大一部分学生读者&#xff0c;以前也分享过一些Java学习路线&#xff0c;但是我收到的反馈并不好&#xff0c;因为学习路线包含的内容太多了&#xff0c;对于初学者来说难度太大&#xff0c;时间也不够用&#xff0c;根本学不完。今天我将结合B站优秀视频整理一期…

英特尔着眼系统工艺协同优化理念,推进摩尔定律新浪潮

Ann Kelleher介绍了晶体管诞生75年之后的新进展 在IEDM 2022&#xff08;2022 IEEE国际电子器件会议&#xff09;全体会议上发表演讲之前&#xff0c;英特尔副总裁兼技术开发总经理Ann Kelleher接受了《IEEE Spectrum》的采访&#xff0c;她表示&#xff0c;摩尔定律的下一波浪…

Tcp/Udp(网络套接字,服务器) -- Linux/Windows

目录 网络传输本质 认识端口号 认识协议 认识TCP协议 认识UDP协议 网络字节序 socket编程接口 socket 常见API sockaddr结构 sockaddr 结构 sockaddr_in 结构 in_addr结构 编写代码前的小tip&#xff08;重点&#xff09; UDP套接字&#xff08;网络通信&#xf…

算法竞赛入门【码蹄集进阶塔335题】(MT2101-2125)

算法竞赛入门【码蹄集进阶塔335题】(MT2201-2225&#xff09; 文章目录算法竞赛入门【码蹄集进阶塔335题】(MT2201-2225&#xff09;前言为什么突然想学算法了&#xff1f;为什么选择码蹄集作为刷题软件&#xff1f;目录1. MT2101 竹鼠发瓜子2. MT2102 竹鼠发瓜子&#xff08;二…

Raft协议

Raft协议先行了解 总体过程速览 假设我们只使用一个节点&#xff0c;可以很容易的达成协议或者共识。 但是现在我们思考&#xff0c;假如有多个节点呢&#xff1f; 多个节点之间达成协议或者共识就叫做分布式共识。 而Raft就是一个实现分布式共识的协议。 一个节点可以有3…

数字化转型的十大好处

前言&#xff1a; 在过去的几年中&#xff0c;“适者生存”对企业来说是至关重要的。不能适应环境变化的企业&#xff0c;也将会加速被淘汰的进程。只有从数字化转型中受益的企业才能更好的参与管理和快速调整&#xff0c;这样一来&#xff0c;员工便能够在更高效、更安全的状…

黑盒测试用例设计 - 判定表法

什么是判定表&#xff1f; 判定表法也叫判定驱动法&#xff0c;是分析和表达多逻辑条件下执行不同操作的情况的工作。 应用场合&#xff1a;只要适用于多条件的内容组合与结果分析 它由以下几个内容组成&#xff1a; 条件桩&#xff08;condition stub&#xff09;&#xff1…

LwIP带操作系统的移植

目录 LwIP移植前期准备 LwIP移植流程 修改lwipopts.h 修改lwip_comm.c文件 修改ethernetif.c/h文件 修改ethernetif_input函数 修改ethernet.c文件 添加应用程序 LwIP是支持操作系统的&#xff0c;在操作系统的支持下我们可以使用LwIP提供的另外两种API编程接口编程。没…