异步CDI事件

几天前,在我们的常规代码审查中,我的一位同事提出了一个问题,即如果可能,一次同时调用CDI观察者(这样的方法带有参数@Observes的方法)会发生什么?用于不同的事件实例。 换句话说,在产生少量事件之后,以下方法是否可能同时被多个线程处理:

public void observe(@Observes MyEvent myEvent) { ... }

考虑一下之后,我决定运行一些测试并在本文中描述结果。

最初的结果:发生了CDI事件以同步模式触发,这让我有些惊讶。 为什么?

到目前为止,我是这样看的:CDI观察者允许我非常干净地将事件生产者与事件消费者分开,因此我没有任何硬编码的侦听器注册,维护侦听器列表并手动通知它们。 CDI容器为我做一切。

因此,如果我们将生产者与消费者完全分开,我认为存在某种事件总线运行在专门的线程执行程序池中,该池负责注册事件与调用的观察者方法之间的中介。 我想我是基于其他事件/侦听器解决方案(例如Google Guava EventBus)的这一假设。 它们使您有机会定义是否要使用同步(默认, EventBus )或异步事件分派器( AsyncEventBus) 。

而且,如果EJB既是生产者又是消费者,那么我认为它具有与异步EJB调用相同的功能。 异步事件观察器唯一可能的JTA事务属性是: REQUIREDREQUIRES_NEWNOT_SUPPORTED

现在,这就是我期望的所有工作方式,这似乎与当前状态大不相同 。 现实生活表明CDI事件是同步的。

使异步事件在CDI 1.1中可用存在一个问题,但是我不确定此功能的当前状态如何,并且在CDI 1.1(Java EE 7的一部分)中没有找到有关此功能的信息。

让我们看看如何独自处理它。

目录

  1. 默认同步事件
  2. 解决方案1 ​​– CDI生产者和Singleton EJB作为接收者
  3. 解决方案2 –使用Singleton EJB作为具有读取锁定的接收器
  4. 解决方案3 – EJB生产者和CDI使用者
  5. 解决方案4 – EJB生产者和EJB使用者
  6. 解决方案4与解决方案2
  7. 解决方案5 – EJB生产者和CDI使用者II
  8. 解决方案6 –使用JMS进行CDI
  9. 结论

默认同步事件

让我们从显示问题的基本示例开始。 看一下代码–首先,CDI Bean生产者:

@Path("/produce")
public class EventGenerator {@Injectprivate Logger logger;@Injectprivate Event<MyEvent> events;@Path("/cdiBean/{eventsNum}")@GETpublic String generateEvents(@PathParam("eventsNum") int numberOfEventsToGenerate) {for (int i = 0; i < numberOfEventsToGenerate; i++) {MyEvent event = new MyEvent(i);logger.info("Generating Event: " + event);events.fire(event);}return "Finished. Generated " + numberOfEventsToGenerate + " events.";}
}

MyEvent只是一些事件对象,在这里并不是很重要。 它存储我们在实例化时传递的事件序列号。

消费者是一个非常简单的CDI Bean:

public class EventConsumer {@Injectprivate Logger logger;public void consumeEvent(@Observes MyEvent myEvent) throws InterruptedException {logger.info("Receiving event: " + myEvent);TimeUnit.MILLISECONDS.sleep(500);}
}

请注意,我已经插入了一个线程睡眠来模拟一些长时间运行的事件接收器进程。

现在,让我们通过调用EventProducer公开的REST命令来运行此示例。 结果(运行JBoss EAP 6.1 Alpha )将类似于以下内容:

14:15:59,196 [com.piotrnowicki.EventGenerator](http- / 127.0.0.1:8080-1)生成事件:MyEvent [ seqNo = 0 ] 14:15:59,197 [com.piotrnowicki.EventConsumer](http- / 127.0 .0.1:8080-1)接收事件:MyEvent [ seqNo = 0 ] 14:15:59,697 [com.piotrnowicki.EventGenerator](http- / 127.0.0.1:8080-1)生成事件:MyEvent [ seqNo = 1 ] 14 :15:59,698 [com.piotrnowicki.EventConsumer](http- / 127.0.0.1:8080-1)接收事件:MyEvent [ seqNo = 1 ] 14:16:00,199 [com.piotrnowicki.EventGenerator](http- / 127.0。 0.1:8080-1)生成事件:MyEvent [ seqNo = 2 ] 14:16:00,200 [com.piotrnowicki.EventConsumer](http- / 127.0.0.1:8080-1)接收事件:MyEvent [ seqNo = 2 ]

它显示了CDI事件的同步性质–事件的产生和使用发生在同一线程中,一个接一个地发生。

那么,如何使用CDI实现异步事件?

解决方案1 ​​– CDI生产者和Singleton EJB作为接收者

生产者坚持使用–纯CDI bean:

@Path("/produce") public class EventGenerator {@Path("/cdiBean/{eventsNum}")@GETpublic String generateEvents(@PathParam("eventsNum") int numberOfEventsToGenerate) { ... }
}

现在,如果您将接收器变成@Singleton EJB,并将observes方法标记为@Asynchronous,如下所示:

@Singleton
public class EventConsumer {@Asynchronouspublic void consumeEvent(@Observes MyEvent myEvent) throws InterruptedException { ...  }
}

您将得到以下结果:

14:21:19,341 [com.piotrnowicki.EventGenerator](http- / 127.0.0.1:8080-1)生成事件:MyEvent [seqNo = 0] 14:21:19,343 [com.piotrnowicki.EventGenerator](http- / 127.0 .0.1:8080-1)生成事件:MyEvent [seqNo = 1] 14:21:19,343 [com.piotrnowicki.EventGenerator](http- / 127.0.0.1:8080-1)生成事件:MyEvent [seqNo = 2] 14 :21: 19,347 [com.piotrnowicki.EventConsumer](EJB默认– 2)接收事件:MyEvent [seqNo = 1] 14:21: 19,848 [com.piotrnowicki.EventConsumer](EJB默认– 1)接收事件:MyEvent [seqNo = 0] 14:21: 20,350 [com.piotrnowicki.EventConsumer](EJB默认值– 3)接收事件:MyEvent [seqNo = 2]

事件是一个接一个地产生的,并且是在单独的线程中产生的。SingletonEJB一次又一次地为它们提供服务(请查看事件处理的时间。)这是因为Singleton EJB的每个业务方法都具有隐式写锁定。 因此,这是:

异步:
线程安全的观察者方法:

解决方案2 –使用Singleton EJB作为具有读取锁定的接收器

这种方法与解决方案1非常相似,但是,由于所有事件处理都是并行进行的,因此它为您提供了更高的吞吐量。

我们的生产者保持不变–它是一个CDI bean:

@Path("/produce")
public class EventGenerator {@Path("/cdiBean/{eventsNum}")@GETpublic String generateEvents(@PathParam("eventsNum") int numberOfEventsToGenerate) { ... }
}

我们的使用者将@Lock(READ)添加到其@Lock(READ)方法中; 这使得能够同时处理多个事件的魔力:

@Singleton
public class EventConsumer {@Asynchronous@Lock(LockType.READ)public void consumeEvent(@Observes MyEvent myEvent) throws InterruptedException { ... }
}

结果就是这样:

14:24:44,202 [com.piotrnowicki.EventGenerator](http- / 127.0.0.1:8080-1)生成事件:MyEvent [seqNo = 0] 14:24:44,204 [com.piotrnowicki.EventGenerator](http- / 127.0 .0.1:8080-1)生成事件:MyEvent [seqNo = 1] 14:24:44,205 [com.piotrnowicki.EventGenerator](http- / 127.0.0.1:8080-1)生成事件:MyEvent [seqNo = 2] 14 :24: 44,207 [com.piotrnowicki.EventConsumer](EJB默认– 4)接收事件:MyEvent [seqNo = 0] 14:24: 44,207 [com.piotrnowicki.EventConsumer](EJB默认– 6)接收事件:MyEvent [seqNo = 2] 14:24: 44,207 [com.piotrnowicki.EventConsumer](EJB默认值– 5)接收事件:MyEvent [seqNo = 1]

同时服务事件的不同线程为您提供更大的吞吐量。 因此,这是:

异步:
线程安全的观察者方法:

解决方案3 – EJB生产者和CDI使用者

CDI允许您观察特定交易阶段的事件。 您可以使用@Observes(during=TransactionPhase...)指定它。 在我们的情况下,我们希望CDI堆叠所有这些事件并仅在事务结束后才调用观察者。 为此,我们只需将以上属性添加到我们的CDI Bean观察器中:

public class EventConsumer { public void consumeEvent(@Observes(during = TransactionPhase.AFTER_COMPLETION) MyEvent myEvent) { ... } 
}

现在,我们只需要确保EventGenerator方法中有正在运行的事务EventGenerator 。 我们可以通过将CDI Bean转换为@Stateless EJB并使用其隐式REQUIRED TransactionAttribute来快速完成此操作:

@Stateless
@Path("/produce")
public class EventGenerator {@Path("/cdiBean/{eventsNum}")@GETpublic String generateEvents(@PathParam("eventsNum") int numberOfEventsToGenerate) { ... }
}

这是我们可能最终得到的结果:

14:39:06,776 [com.piotrnowicki.EventGenerator](http- / 127.0.0.1:8080-1)生成事件:MyEvent [seqNo = 0] 14:39:06,776 [com.piotrnowicki.EventGenerator](http- / 127.0 .0.1:8080-1)生成事件:MyEvent [seqNo = 1] 14:39:06,776 [com.piotrnowicki.EventGenerator](http- / 127.0.0.1:8080-1)生成事件:MyEvent [seqNo = 2] 14 :39: 06,778 [com.piotrnowicki.EventConsumer](http- / 127.0.0.1:8080-1)接收事件:MyEvent [seqNo = 2] 14:39: 07,279 [com.piotrnowicki.EventConsumer](http- / 127.0。 0.1:8080-1)接收事件:MyEvent [seqNo = 0] 14:39: 07,780 [com.piotrnowicki.EventConsumer](http- / 127.0.0.1:8080-1)

EJB EventGenerator启动事务,并且只有在事务完成之后,才会以序列化的方式调用CDI bean观察器。

异步:
线程安全的观察者方法:

解决方案4 – EJB生产者和EJB使用者

这与解决方案3非常相似。我们的生成器保持不变(无状态EJB):

@Stateless
@Path("/produce")
public class EventGenerator {@Path("/cdiBean/{eventsNum}")@GETpublic String generateEvents(@PathParam("eventsNum") int numberOfEventsToGenerate) { ... }
}

现在对EventConsumer进行了更改:

@Singleton
public class EventConsumer {@Asynchronous@Lock(LockType.READ)public void consumeEvent(@Observes(during = TransactionPhase.AFTER_COMPLETION) MyEvent myEvent) throws InterruptedException { ...  }
}

结果可能如下:

14:44:09,363 [com.piotrnowicki.EventGenerator](http- / 127.0.0.1:8080-1)生成事件:MyEvent [seqNo = 0] 14:44:09,464 [com.piotrnowicki.EventGenerator](http- / 127.0 .0.1:8080-1)生成事件:MyEvent [seqNo = 1] 14:44:09,564 [com.piotrnowicki.EventGenerator](http- / 127.0.0.1:8080-1)生成事件:MyEvent [seqNo = 2] 14 :44: 09,670 [com.piotrnowicki.EventConsumer](EJB默认– 8)接收事件:MyEvent [seqNo = 2] 14: 4409,670 [com.piotrnowicki.EventConsumer](EJB默认– 2)接收事件:MyEvent [seqNo = 1] 14:44: 09,670 [com.piotrnowicki.EventConsumer](EJB默认– 1)接收事件:MyEvent [seqNo = 0]

我们在这里使用了两个功能–一个是事件使用者方法是异步的,第二个是在生产者事务完成之前不会通知使用者。 这给我们:

异步:
线程安全的观察者方法:

解决方案4与解决方案2

这两个解决方案似乎是相同的。 它们仅与消费者的注释不同: @Observes@Observes(during = TransactionPhase.AFTER_COMPLETION) 。 此外,对于我们的测试用例,它们的行为相同: 它们是异步的,并且多个线程可以同时处理事件接收器 。 但是,它们之间有一个很大的区别。

在我们的测试案例中,我们一个接一个地触发事件。 想象一下,事件触发之间还有其他操作。 在这种情况下:

  • 解决方案2( @Observes )将在第一个事件触发后立即开始处理事件,
  • 解决方案4( @Observes(during = TransactionPhase.AFTER_COMPLETION) )将在事务完成后立即开始处理,因此将触发所有事件。

这显示了这种情况的可能结果:

解决方案2( @Observes

15:01:34,318 [com.piotrnowicki.EventGenerator](http- / 127.0.0.1:8080-1)生成事件:MyEvent [ seqNo = 0 ] 15:01:34,320 [com.piotrnowicki.EventConsumer](EJB默认– 3 )接收事件:MyEvent [ seqNo = 0 ] 15:01:34,419 [com.piotrnowicki.EventGenerator](http- / 127.0.0.1:8080-1)生成事件:MyEvent [ seqNo = 1 ] 15:01:34,420 [com .piotrnowicki.EventConsumer](EJB默认– 6)接收事件:MyEvent [ seqNo = 1 ] 15:01:34,520 [com.piotrnowicki.EventGenerator](http- / 127.0.0.1:8080-1)生成事件:MyEvent [ seqNo = 2 ] 15:01:34,521 [com.piotrnowicki.EventConsumer](EJB默认值– 9)接收事件:MyEvent [ seqNo = 2 ]

解决方案4( @Observes(during = TransactionPhase.AFTER_COMPLETION)

15:00:41,126 [com.piotrnowicki.EventGenerator](http- / 127.0.0.1:8080-1)生成事件:MyEvent [ seqNo = 0 ] 15:00:41,226 [com.piotrnowicki.EventGenerator](http- / 127.0 .0.1:8080-1)生成事件:MyEvent [ seqNo = 1 ] 15:00:41,326 [com.piotrnowicki.EventGenerator](http- / 127.0.0.1:8080-1)生成事件:MyEvent [ seqNo = 2 ] 15 :00:41,432 [com.piotrnowicki.EventConsumer](EJB默认– 10)接收事件:MyEvent [ seqNo = 2 ] 15:00:41,432 [com.piotrnowicki.EventConsumer](EJB默认– 4)接收事件:MyEvent [ seqNo = 1 ] 15:00:41,432 [com.piotrnowicki.EventConsumer](EJB默认值– 5)接收事件:MyEvent [ seqNo = 0 ]

解决方案5 – EJB生产者和CDI使用者II

到目前为止,我们已经尝试使接收器异步。 也有相反的方法–我们可以使事件生成器异步 。 我们可以通过将生产者标记为@Stateless并调用自己的异步方法来触发事件来实现:

@Stateless
@Path("/produce")
public class EventGenerator {// ...@Resourceprivate SessionContext sctx;@Path("/cdiBean/{eventsNum}")@GETpublic String generateEvents(@PathParam("eventsNum") int numberOfEventsToGenerate) {for (int i = 0; i < numberOfEventsToGenerate; i++) {sctx.getBusinessObject(EventGenerator.class).fireEvent(new MyEvent(i));}return "Finished. Generated " + numberOfEventsToGenerate + " events.";}@Asynchronouspublic void fireEvent(final MyEvent event) {events.fire(event);}
}

使用SessionContext仔细研究EJB自动引用。 在这种情况下,这是必需的,因为我们希望容器分派我们的方法调用并添加它的异步性质。 我们不希望使之成为本地呼叫,所以我们拒绝使用隐含的this对象。
另一方面,事件使用者是纯CDI bean:

public class EventConsumer {public void consumeEvent(@Observes MyEvent myEvent) throws InterruptedException { ... }
}

结果可能如下:

00:40:32,820 [com.piotrnowicki.EventGenerator](EJB默认– 2)正在生成事件:MyEvent [seqNo = 1] 00:40:32,820 [com.piotrnowicki.EventGenerator](EJB默认– 3)正在生成事件:MyEvent [ SEQNO = 2] 00:40:32820 [com.piotrnowicki.EventGenerator](EJB默认- 1)产生事件:MyEvent [SEQNO = 0] 00:40:32821 [com.piotrnowicki.EventConsumer](EJB默认- 1)接收事件:MyEvent [seqNo = 0] 00 : 4032,821 [com.piotrnowicki.EventConsumer](EJB默认– 2)接收事件:MyEvent [seqNo = 1] 00 : 4032,821 [com.piotrnowicki.EventConsumer](EJB默认– 3)接收事件:MyEvent [seqNo = 2]

异步:
线程安全的观察者方法:

解决方案6 –使用JMS进行CDI

这是Juliano Viana在他的博客上提出的解决方案。 它使用JMS作为事件总线。 生成CDI事件,然后由负责将该事件放入JMS主题/队列的某个类获取。 从主题/队列中获取消息的MDB正在生成一个调用实际接收者的事件。 这不仅为您提供了事件的异步传递,而且还为其添加了事务性质。 例如,如果事件接收者无法处理该消息–它可以回滚该事务,并且队列将确保该消息将被重新发送(也许您的事件处理器下次将能够处理此事件?)

结论

CDI 1.0不支持异步事件生成。 CDI 1.1似乎也没有这种支持。

但是,这并不意味着您无法实现异步处理。 已经存在基于EJB 3.1或现有CDI观察器属性的现有解决方案。 您还应该能够编写可移植的CDI扩展 ,以将此功能添加到代码中。

参考: Piotr Nowicki博客博客上的JCG合作伙伴 Piotr Nowicki提供了异步CDI事件 。

翻译自: https://www.javacodegeeks.com/2013/05/asynchronous-cdi-events.html

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

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

相关文章

oracle改了包怎么保存,Oracle存储过程、包、方法使用总结(推荐)

/***author&#xff1a;zhengwei*date:2017-04-28*desc:存储过程用法总结*/CREATE OR REPLACE PROCEDURE MYPROCEDURE(P_ID IN VARCHAR,P_STATUS OUT VARCHAR) --P_ID为输入参数 ,P_STATUS为输出参数AS---变量声明T_STATUS VARCHAR2(20);T_ID NUMBER;V_POSTYPE VARCHAR2(20);V_…

【2017级面向对象程序设计】第2次成绩排行

作业地址 https://edu.cnblogs.com/campus/fzu/OOP/homework/1864 评分标准 1&#xff09; C 流程图 or 文字描述程序结构 5分C 类图 or 文字描述程序结构 5分2&#xff09; 代码 共 10 分构造函数 &#xff1a;2 分析构函数 &#xff1a;2 分成员函数 显示当前所处楼层&#x…

css定位position

闲言碎语不多说&#xff0c;直接开写&#xff01; 关于定位 我们可以使用css的position属性来设置元素定位类型&#xff0c;position的设置项如下&#xff1a; a、relative生成相对定位元素&#xff0c;元素所占据的文档流的位置不变&#xff08;即元素不会脱离文档流&#x…

Spring Security登录

1.简介 本文将重点介绍使用Spring Security登录 。 我们将在前面的简单Spring MVC示例的基础上构建&#xff0c;因为这是设置Web应用程序和登录机制的必要部分。 2. Maven依赖 要将Maven依赖项添加到项目中&#xff0c;请参阅Spring Security with Maven文章 。 标准的spring-…

php运城,运城php培训

作用域&#xff1a;全局的request恳求   描绘&#xff1a;经过在Global中完成Application_Error办法&#xff0c;来到达侦听未经处置的异常   详细代码如下&#xff1a;sudo dtrace -qFn pid$target:Finding?Ray:Finding?Ray:r{ printf("%s\n", probefunc); } …

sql语句使用、说明及技巧

一、基础 1、说明&#xff1a;创建数据库CREATE DATABASE database-name 2、说明&#xff1a;删除数据库drop database dbname3、说明&#xff1a;备份sql server--- 创建 备份数据的 deviceUSE masterEXEC sp_addumpdevice disk, testBack, c:\mssql7backup\MyNwind_1.dat--- …

利用爬虫模拟网页微信wechat

1.登录页面&#xff0c;显示二维码 当我们打开网页微信时&#xff0c;会看到一个用于扫码登录的二维码&#xff0c;所以我们要模拟该页面给我们的页面也弄一个二维码 通过查看网页代码我们发现&#xff0c;这个二维码的标签为 这个src属性的最后一段每次访问都是不同的&#xf…

Bootstrap分页

前面的话 分页导航几乎在每个网站都可见&#xff0c;好的分页能给用户带来好的用户体验。本文将详细介绍Bootstrap分页 概述 在Bootstrap框架中提供了两种分页导航&#xff1a; ☑ 带页码的分页导航 ☑ 带翻页的分页导航 页码分页 带页码的分页导航&#xff0c;可能是最常见…

php 查询and or,php – SQL查询多个AND和OR不起作用

我有一个包含由双管分隔的值的单元格.我试图用以下内容搜索这个单元格的内容,(其中10是要搜索的数字)&#xff1f;,10&#xff05;,&#xff1f;&#xff05;和10我的查询似乎只返回10.没有其他变化.有人可以告诉我为什么它不起作用&#xff1f;提前谢谢了. (您在下面看到的SQL…

[codevs1213]解的个数 二分 + exgcd

题目← 扩欧&#xff0c;求不定方程解的个数 我们已经知道通解x0 x - (b/gcd(a,b))t&#xff0c;那只要知道有多少个t使x在题目给定的范围中就行了 但还有y 怎么办&#xff1f;求交集&#xff01; 分别二分确定在x取值范围内合法的t的范围和在y取值范围内合法的t的范围 然后交…

爬取饿了么商铺信息

分析&#xff1a; 当我们访问https://www.ele.me/home/时&#xff0c;看看我们得到了什么 1.png我们发现所有的城市名称和他的经纬度&#xff0c;还有一个风流的男子 然后随机输入一些东西看看&#xff0c;进入某个地区看一看 在新的界面里我们看到了这样一条url: https://main…

html中的锚点

一、页面内跳转的锚点设置 页面内的跳转需要两步&#xff1a; 方法一&#xff1a; ①&#xff1a;设置一个锚点链接<a href"#miao">去找喵星人</a>&#xff1b;&#xff08;注意&#xff1a;href属性的属性值最前面要加#&#xff09; ②&#xff1a;在页…

linux基本命令du,Linux常用操作命令汇总

你还在为不知道Linux常用操作命令汇总而不知所措么?下面来是学习啦小编为大家收集的Linux常用操作命令汇总&#xff0c;欢迎大家阅读&#xff1a;Linux常用操作命令汇总1.ls 命令ls以默认方式显示当前目录文件列表服务器教程ls -a显示所有文件包括隐藏文件ls -l显示文件属性&a…

Maven部署到Nexus

1.概述 在上一篇文章中 &#xff0c;我讨论了Maven项目如何在本地安装尚未部署在Maven Central&#xff08;或任何其他大型且公共托管的存储库&#xff09;上的第三方jar。 该解决方案仅适用于小型项目&#xff0c;在这些项目中安装&#xff0c;运行和维护完整的Nexus服务器可能…

后处理效果栈

Unity官方的Github实现&#xff1a;Post Processing Stack Post-processing is the process of applying full-screen filters and effects to a camera’s image buffer before it is displayed to screen. It can drastically improve the visuals of your product with litt…

【Java IO流】浅谈io,bio,nio,aio

本文转载自&#xff1a;http://www.cnblogs.com/doit8791/p/4951591.html1、同步异步、阻塞非阻塞概念 同步和异步是针对应用程序和内核的交互而言的。 阻塞和非阻塞是针对于进程在访问数据的时候&#xff0c;根据IO操作的就绪状态来采取的不同方式&#xff0c;说白了是一种读…

linux 安装tcl命令,TCL/TK Linux下安装 | 勤奋的小青蛙

原创文章&#xff0c;转载请注明&#xff1a; 转载自勤奋的小青蛙本文链接地址: TCL/TK Linux下安装在Linux下安装TCL/TK&#xff0c;可以有编译源代码的方式安装&#xff0c;也可以有直接通过二进制压缩包进行解压缩安装&#xff0c;本文采用比较快捷的方式&#xff0c;用二进…

安全性中的Spring AOP –通过方面控制UI组件的创建

以下文章将显示在我参与的一个项目中&#xff0c;我们如何使用Spring的AOP来介绍一些与安全性相关的功能。 这样的概念是为了使用户能够看到一些UI组件&#xff0c;他需要具有一定级别的安全特权。 如果不满足该要求&#xff0c;则不会显示UIComponent。 让我们看一下项目结构&…

模拟生物自然进化的基因遗传算法

基因遗传算法&#xff08;Genetic Algorithm&#xff0c;GA&#xff09;是一种通过模拟生物进化过程来寻找最优解的优化算法。它是一种常见的启发式搜索算法&#xff0c;常用于优化、搜索和机器学习等领域。 生物基因遗传 生物的基因遗传是指父母通过基因传递给子代的过程。基因…

折半查找算法及分析(手工过程)

折半查找的手工过程&#xff1a; 1.我需要查找的数是10&#xff1b; 给定&#xff1a;1 5 8 10 13 14 17 22 25 27 29 31 35 37 40 42 45 47 50 51 58 下标&#xff1a;0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1…