php cdi_异步CDI事件

php 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]

事件是一个接一个地产生的,并且在单独的线程中,Singleton EJB一次又一次地为它们提供服务(请查看事件处理的时间。)这是因为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 = 2 ] = 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

php cdi

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

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

相关文章

tg3269c网卡驱动linux,TP-Link3269C网卡驱动官方版

TG-3269C驱动是一款能够安装于由普联发布的无线网卡驱动&#xff0c;通过此安装驱动我们手机和其他无线设备才能连接上无线网卡并进行上网&#xff0c;同时如果你的网卡经常出现断开和重连、网络不稳定等情况可以通过重新安装驱动&#xff0c;查看是否是硬件的问题&#xff0c;…

使用Spring Security,Thymeleaf和Okta保护Java应用程序的安全

永不再构建身份验证 –喜欢构建用户管理&#xff1f; 使用Okta&#xff0c;您可以在几分钟内为您的应用程序添加社交登录&#xff0c;多因素身份验证和OpenID Connect支持。 立即创建一个免费的开发者帐户。 在构建Java应用程序时&#xff0c;用户管理是至关重要的考虑因素。 …

红旗linux添加usb无线网卡,在Ubuntu 8.10中安装无线网卡RTL8187SE驱动

本人的笔记本是微星的Wind U90&#xff0c;自带的无线网卡是RTL8187SE。这款无线网卡在一般的Linux下是没有驱动的&#xff0c;微星的官方也仅仅提供在OpenSUSE下的驱动。为了在我的Ubuntu下使用这个网卡&#xff0c;只能自己动手了。还好&#xff0c;有了互联网上各位大侠和微…

java linq_LINQ和Java

java linqLINQ已经非常成功&#xff0c;但在.NET生态系统中也引起了争议。 许多人正在Java世界中寻找可比的解决方案。 为了更好地理解什么是可比的解决方案&#xff0c;让我们看一下LINQ解决的主要问题&#xff1a; 查询语言通常是具有许多关键字的声明性编程语言。 它们提供…

嵌入式 linux restful,嵌入式 RESTful 框架 express.java

软件介绍express.java 是一个微型的 RESTful Web 框架。可用于嵌入应用内部&#xff0c;替代 JMX 用于跨语言通讯。示例代码&#xff1a;WebServer.jettyServer().get("/", new AjaxController() {Overridepublic Object ajax(ParamMap params) {return ResultMap.cr…

将Google reCaptcha与Spring Boot应用程序结合使用

介绍 Google的reCaptcha是一个用于防止漫游器向您的公共表单提交数据或访问您的公共数据的库。 在本文中&#xff0c;我们将研究如何将reCaptcha与基于Spring Boot的Web应用程序集成 设置验证码 您应该从管理面板创建API密钥。 您必须创建一个示例应用程序&#xff0c;如下所…

探索 HTTP 请求的世界:get 和 post 的奥秘(上)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

linux 书签管理工具,在书签管理工具中使用Ubuntu字体

通过便捷书签管理程序(Bookmarklet&#xff0c;一种在浏览器中存放书签URL地址的应用程序)来在大多数的网站上推广使用Ubuntu系统的默认字体。——读者米格尔费尔南迪斯米格尔在他的想法产生之前告诉我们说&#xff1a;“我发现Ubuntu系统的字体在提高可读性上超过了绝大多数的…

linux18.2安装界面,Ubuntu 18.10下安装Grub Customizer 5.1.0配置grub2图形化界面

配置Grub2/burg引导装载程序Grub Customizer 5.1.0新增加对Ubuntu 18.10的支持&#xff0c;我们可以用PPA源来安装&#xff0c;同时还支持Ubuntu 18.04、16.04、14.04。Grub Customizer简介Grub Customizer是用来配置Grub/burg引导装载程序的图形工具&#xff0c;此次发布的5.1…

使用Eclipse和Open Liberty的Java EE 8上的Java 9

几周前&#xff0c;我写了一篇文章&#xff0c;标题为哪个IDE和服务器支持Java EE 8和Java9 &#xff0c;着眼于Java 9和Java EE 8之间的当前运行状态。您可以期待事情发展很快&#xff0c;我们现在有了一些alpha和支持Java 9和Java EE 8的开发版本。这些是– Payara 5 –适用…

深入浅出linux工具与编程 下载,8208.深入浅出Linux工具与编程.pdf

<>猛点这里下载全部内容目录&#xff1a;第1篇Linux命令及其工具第1章Linux系统与命令1.1Linux操作系统1.1.1Linux重要概念1.1.2Linux组成1.1.3Linux目录结构1.1.4Linux操作系统的组成1.1.5Linux用户管理1.1.6Linux文件管理1.2Linux命令1.2.1Linux命令帮助1.2.2Linux命令…

linux删除含有特殊字符的行,Linux 删除带有特殊字符的文件

禁止页面后退JS(兼容各浏览器)XML中&lt&semi;beans&gt&semi;中属性概述

使用SpringWebFlux的反应式Web应用程序

1.反应式编程简介 反应式编程是为具有以下特征的应用程序创造的术语&#xff1a; 非阻塞应用 事件驱动和异步 需要少量线程来垂直扩展&#xff08;即在JVM中&#xff09; 就像面向对象的编程&#xff0c;函数式编程或过程式编程一样&#xff0c;反应式编程只是另一种编程范…

对linux的mv命令设计测试用例,测试用例中的细节 - 八音弦的个人空间 - OSCHINA - 中文开源技术交流社区...

编写测试用例是在实际测试执行开始之前进行的软件测试活动的重要组成部分。因此&#xff0c;在编写测试用例时必须头脑清晰地理解需求。测试执行阶段的顺利程度主要取决于测试用例的编写质量&#xff0c;还取决于对需求的理解程度。理论上来讲应避免在测试用例中放入不必要或不…

linux python whl md5,Python计算一个目录下的所有文件的md5值,在Linux系统下面

实现代码如下&#xff1a;#!/usr/bin/python#*-*coding:utf8*-*import osimport sysimport hashlibdef md5sum(data):with open(data, "rb") as f:md5 hashlib.md5() #赋空值for i in f.read(4096): #防止遇到大文件打开太占用内存&#xff0c;所以一次打开4…

Java命令行界面(第28部分):getopt4j

getopt4j的页面将其描述为“一个根据GNU样式解析命令行参数的库。” 然后&#xff0c; 页面介绍getopt4j &#xff1a;“getopt4j库旨在以与glibc &#xff08;GNU C运行时库&#xff09;中的C getopt&#xff08;&#xff09;函数相同的方式解析命令行选项。 与原始产品相比&a…

c语言找出公共子字符串,经典C语言面试题:求解最大公共子串

今天去面试&#xff0c;面试官出了一道题&#xff0c;求两个字符串的最大公共子串(Longest Common Substring)&#xff0c;一听起来不是很难&#xff0c;但让我在纸上写着写着就迷糊了。回来特地网搜了一下。面试下面经过两种方法来求两个字符串的最大连续公共子串。数组方法1&…

c语言中如何防止输入的格式存在错误,C语言如何避免输入

C语言如何处理输入下面这个题&#xff0c;数据的处理很简单&#xff0c;方法也很多。但是数据的输入如何处理呢&#xff0c;还要分多行输入&#xff01;&#xff01;引用标题&#xff1a;错误票据某涉密单位下发了某种票据&#xff0c;并要在年终全部收回。每张票据有唯一的ID号…

lucene 增加相关性_事务性Lucene

lucene 增加相关性许多用户不喜欢Lucene API的事务性语义&#xff0c;以及这在搜索应用程序中如何有用。 首先&#xff0c;Lucene实现了ACID属性&#xff1a; 一个 tomicity&#xff1a;当您在更改&#xff08;添加&#xff0c;删除文件&#xff09; IndexWriter会话&#xff…

新版ipados可以编辑C语言吗,iPadOS新增了五个有用的功能,看你需不需要

主屏幕上的可自定义小部件苹果通过“ iOS 14”对“小工具”进行了大修&#xff0c;引入了新的设计&#xff0c;功能和自定义选项。这些“小部件”也出现在在iPhone上&#xff0c;您可以抓住任何小部件并将其添加到应用程序图标旁边的“主屏幕”中&#xff0c;但是不能在“ iPad…