react性能优化方案_React灵敏且性能卓越的Spray + Akka解决方案,以“在Java和Node.js中发挥并发性和性能”...

react性能优化方案

在我以前的文章中,我研究了一个虚拟的交易引擎,并将基于Java的阻止解决方案与基于Node.js的非阻止解决方案进行了比较。 在文章的结尾,我写道:

我怀疑随着Node.js的最近成功,越来越多的异步Java库将开始出现。

这样的库已经存在,例如: Akka , Spray和此Mysql异步驱动程序 。

我给自己设定了一个挑战,即要确切地使用这些库来创建基于Java的非阻塞解决方案,以便将其性能与上一篇文章中创建的Node.js解决方案的性能进行比较。 您可能注意到的第一件事是这些都是基于Scala的库,但是我用Java编写了该解决方案,尽管它在语法上不太优雅。 在上一篇文章中,我介绍了一种基于Akka的解决方案,该解决方案将交易引擎封装在actor中。 在这里,我放弃了Tomcat作为HTTP服务器,而将其替换为Spray,后者将HTTP服务器直接集成到Akka中。 从理论上讲,这不会对性能造成任何影响,因为Spray是NIO,就像Tomcat 8一样。 但是吸引我到此解决方案的是,总体而言,线程的数量大大减少了,因为Spray,Akka和异步Mysql库都使用相同的执行上下文 。 Tomcat在我的Windows开发机器上运行,有30多个线程,而此处构建的解决方案只有10个以上,或者与Websphere或JBoss相比有数百个线程。 执行上下文基本上是一个线程池,这些线程运行分配给它的任务。 由于此处介绍的解决方案中使用的所有库都是非阻塞的,因此线程数可以保持较低并接近理论最佳值,从而尽可能少地进行上下文切换 ,从而使过程高效运行。

本文编写的代码在GitHub上 。 该程序的第一部分是启动Spray和Akka的main方法:

public static final ActorSystem system = ActorSystem.create("system");public static void main(String[] args) {...ActorRef listener = system.actorOf(Props.create(HttpActor.class), "httpActor"); InetSocketAddress endpoint = new InetSocketAddress(3000);int backlog = 100;List<Inet.SocketOption> options = JavaConversions.asScalaBuffer(new ArrayList<Inet.SocketOption>()).toList();Option<ServerSettings> settings = scala.Option.empty();ServerSSLEngineProvider sslEngineProvider = null;Bind bind = new Http.Bind(listener, endpoint, backlog, options, settings, sslEngineProvider);IO.apply(spray.can.Http$.MODULE$, system).tell(bind, ActorRef.noSender());system.scheduler().schedule(new FiniteDuration(5, TimeUnit.SECONDS), new FiniteDuration(5, TimeUnit.SECONDS), ()->{System.out.println(new Date() + " - numSales=" + numSales.get());}, system.dispatcher());
}

第1行创建了一个actor系统,它是公共的,因此我可以从其他地方访问它,因为它用于访问我想在整个程序中使用的单个执行上下文。 (在存在可维护性问题的代码中,我会写一些东西,以便将该对象注入程序的相关部分。)然后,第5行使用该系统实例化一个actor,该actor用于处理所有HTTP买卖请求。命令。 第7-11行仅设置了服务器的配置数据。 第12和13行是我们进行配置和actor的地方,然后告诉Akka IO使用它们和HTTP模块从第5行将所有HTTP请求作为消息发送给我们的actor。15-17行是我有效地设置计时器任务的地方每5秒触发一次以输出一些统计信息。 这里重要的一点是要注意,我没有使用Java的Timer来调度任务,因为那只会给我的进程添加更多不必要的线程。 相反,我使用与Akka相同的执行上下文,因此创建了尽可能少的线程。

接下来是处理HTTP请求的参与者:

private static class HttpActor extends AbstractActor {private static final HttpProtocol HTTP_1_1 = HttpProtocols.HTTP$div1$u002E1();public HttpActor() {final Router router = partitionAndCreateRouter();receive(ReceiveBuilder.match(HttpRequest.class, r -> {int id = Constants.ID.getAndIncrement();String path = String.valueOf(r.uri().path());if("/sell".equals(path)){String productId = r.uri().query().get("productId").get();...SalesOrder so = new SalesOrder(price, productId, quantity, id);so.setSeller(new Seller(who));router.route(so, self());replyOK(id);}else if("/buy".equals(path)){...}else{handleUnexpected(r);}}).match(Tcp.Connected.class, r ->{sender().tell(new Http.Register(self(), Http.EmptyFastPath$.MODULE$), self()); //tell that connection will be handled here!}).build());}

第3行显示了一个示例,该示例显示如何将Scala集成到Java程序中是很丑陋的,但是有时您如何可以通过添加自己的抽象来隐藏那些丑陋的部分。 响应HTTP请求的HTTP actor具有3个作业。 第6行上的第一个工作是在其中创建一个路由器,我将在下面对其进行描述,并将其用于委派工作。 第二项工作是处理24-24行上的所有新连接,这告诉Spray这个参与者也将处理实际的请求,而不仅仅是连接。 该参与者具有的第三项工作在第9-18行中显示,该参与者接受HTTP请求并将一些工作委托(路由)到系统中的另一个参与者。

这个参与者知道HTTP模型,但是HTTP抽象不会泄漏到系统的下一层。 相反,参与者将域对象(或值对象或案例类或类似对象)传递到封装交易引擎的参与者上。 使用从HTTP请求中提取的数据(例如在第13行),或者使用请求主体中的JSON对象,可以在第15和16行看到此类域对象的构造。 Spray包含有用的指令 ,可以帮助您从请求中提取数据,如果需要的话,可以从HTTP提取一些内容。 构造哪个域对象取决于我构建并在第9、12和19行处理的类似REST的接口。如果我使用Scala,则可以在HttpRequest对象上使用模式匹配来编写更精美的代码。 通过从第6行获取路由器以将域对象路由到合适的参与者,将域对象传递到交易引擎,在第17行。最后但并非最不重要的是,第18行是在HTTP响应中确认销售订单请求的位置它将JSON对象以及分配给订单的唯一ID传递给消费者,以便以后可以查询其状态(将其持久化到销售对象中)。

下一个代码片段显示了我们如何划分市场并创建多个参与者来并行处理请求。

private Router partitionAndCreateRouter() {Map<String, ActorRef> kids = new HashMap<>();java.util.List<Routee> routees = new ArrayList<Routee>();int chunk = Constants.PRODUCT_IDS.length / NUM_KIDS;for (int i = 0, j = Constants.PRODUCT_IDS.length; i < j; i += chunk) {String[] temparray = Arrays.copyOfRange(Constants.PRODUCT_IDS, i, i + chunk);LOGGER.info("created engine for products " + temparray);ActorRef actor = getContext().actorOf(Props.create(EngineActor.class));getContext().watch(actor);routees.add(new ActorRefRoutee(actor));for (int k = 0; k < temparray.length; k++) {LOGGER.debug("mapping productId '" + temparray[k] + "' to engine " + i);kids.put(temparray[k], actor);}LOGGER.info("---started trading");actor.tell(EngineActor.RUN, ActorRef.noSender());}			Router router = new Router(new PartitioningRoutingLogic(kids), routees);return router;
}

该代码与上一篇文章中的代码相似。 为了同时扩展和使用多个核心,按产品ID对市场进行了划分,并且每个交易引擎针对不同的市场划分同时运行。 在此处介绍的解决方案中,在每个分区上创建一个EngineActor并将其包装在第10行的Routee中。第14行还填充了一个由产品ID键控的actor映射。在第19行和第19行使用路由和映射构建了路由器。委派工作时HttpActor在上一片段中使用的就是这个。 还要注意第17行,它启动了包含在EngineActor的交易引擎,以便启动并运行该EngineActor ,并准备在将购买和销售订单传递给这些EngineActor进行交易。

这里没有明确显示EngineActor类,因为它与上一篇文章中使用的actor几乎相同,并且仅封装了一个交易引擎,该引擎处理特定市场分区中的所有产品。 上面的第19行使用RoutingLogic构建路由器,如下所示:

public static class PartitioningRoutingLogic implements RoutingLogic {private Map<String, ActorRef> kids;public PartitioningRoutingLogic(Map<String, ActorRef> kids) {this.kids = kids;}@Overridepublic Routee select(Object message, IndexedSeq<Routee> routees) {//find which product ID is relevant hereString productId = null;if(message instanceof PurchaseOrder){productId = ((PurchaseOrder) message).getProductId();}else if(message instanceof SalesOrder){productId = ((SalesOrder) message).getProductId();}ActorRef actorHandlingProduct = kids.get(productId);//no go find the routee for the relevant actorfor(Routee r : JavaConversions.asJavaIterable(routees)){ActorRef a = ((ActorRefRoutee) r).ref(); //cast ok, since the are by definition in this program all routees to ActorRefsif(a.equals(actorHandlingProduct)){return r;}}return akka.routing.NoRoutee$.MODULE$; //none found, return NoRoutee}
}

路由器在接收到必须路由到正确角色的对象时,会调用第10行的select(...)方法。 使用在上一个清单中创建的地图以及从请求中获得的产品ID,很容易找到包含负责相关市场划分的交易引擎的参与者。 通过返回包裹该参与者的路由,Akka会将订单对象传递给正确的EngineActor ,然后在交易引擎处于交易周期之间且EngineActor下次检查时处理该消息时,将数据放入模型中它的收件箱。

好的,这就是要处理的前端。 上一篇文章的解决方案所需的第二个主要更改是方法的设计,该方法可以在交易发生后保持销售。 在基于Java的解决方案中,我同步遍历每个销售并将insert语句发送到数据库,并且仅在数据库回复后才处理下一个销售。 使用此处提供的解决方案,我选择通过向数据库发出insert请求并立即移至下一个销售并执行相同操作来并行处理销售。 使用我提供的回调在执行上下文中异步处理了响应。 我编写了程序,以等待最后一次插入被确认,然后再继续进行新创建的购买和销售订单的交易,该订单自上次交易时段开始以来就已经出现。 在下面的清单中显示:

private void persistSales(List<Sale> sales, final PersistenceComplete f) {if (!sales.isEmpty()) {LOGGER.info("preparing to persist sales");final AtomicInteger count = new AtomicInteger(sales.size());sales.forEach(sale -> {List values = Arrays.asList(sale.getBuyer().getName(), sale.getSeller().getName(),sale.getProductId(),sale.getPrice(),sale.getQuantity(),sale.getPurchaseOrder().getId(),sale.getSalesOrder().getId());Future<QueryResult> sendQuery = POOL.sendPreparedStatement(SQL, JavaConversions.asScalaBuffer(values));sendQuery.onComplete(new JFunction1<Try<QueryResult>, Void>() {@Overridepublic Void apply(Try<QueryResult> t) {if(t.isSuccess()){QueryResult qr = t.get();//the query result doesnt contain auto generated IDs! library seems immature...//sale.setId(???);}if(count.decrementAndGet() == 0){if(t.isSuccess()){f.apply(null);}else{f.apply(t.failed().get());}}return null; //coz of Void}}, Main.system.dispatcher());});}else{f.apply(null); //nothing to do, so continue immediately}
}

交易引擎会在每个交易周期后调用persistSales(...)方法,并向该方法传递在该交易周期内完成的销售清单,并在所有持久性完成后调用一个回调函数。 如果未售出任何东西,则第38行立即调用回调。 否则,在第5行上创建一个计数器,该计数器用要保留的销售数量初始化。 每次销售都在第7-15行异步保存。 请注意,第15行如何返回Future ,以及我们如何在16-35行使用另一个回调来处理future的完成–这里没有阻塞,等待future完成! 上面提到的计数器在第25行递减,一旦销售被持久化,并且所有销售都被持久化,则调用传递给persistSales(...)方法的回调。 请注意,第16行上使用的类JFunction1是一种填充程序,可以更轻松地集成JFunction1代码在GitHub上的上述链接中。 第21和22行表明,我使用的异步Mysql库存在一些问题。 它仍然是一个beta,似乎没有办法掌握销售的已​​生成(自动递增)主键。 还要注意第35行,在这里我传递了Akka使用的执行上下文,以便处理插入语句完成的Future在一个现有线程上而不是某个新线程上进行处理-再次,保持总数线程越低越好。

该清单还显示了一个有趣的问题,即调用数据库以插入数据的线程不一定是可能需要关闭连接的线程[1]。 在普通的Java EE和Spring中,经常使用线程本地存储(另请参见此处 )。 如果您从处理将来完成的函数中调用Bean,则注入到其中的资源可能不起作用,因为容器无法确定上下文是什么。 Scala使用隐式参数解决了这个问题,该参数在后台传递给方法。

上面的清单使用PersistenceComplete回调,如下面第14-16行所示。 它还使用使用以下代码创建的连接池。 再一次,Akka使用的执行上下文将传递到下面第10行的异步Mysql库。 下面的第10行还显示了一个非默认的池配置,其中允许的最大队列大小最大为一千。 在负载测试期间,我收到许多错误消息,表明池已饱和,增加该值可以解决问题。

private static final String SQL = "INSERT INTO SALES (BUYER_NAME, SELLER_NAME, PRODUCT_ID, PRICE, QUANTITY, PO_ID, SO_ID) VALUES (?, ?, ?, ?, ?, ?, ?)";private static final ConnectionPool<MySQLConnection> POOL;
static {Duration connectTimeout = Duration.apply(5.0, TimeUnit.SECONDS);Duration testTimeout = Duration.apply(5.0, TimeUnit.SECONDS);Configuration configuration = new Configuration("root", Main.DB_HOST, 3306, Option.apply("password"), Option.apply("TRADER"), io.netty.util.CharsetUtil.UTF_8, 16777216, PooledByteBufAllocator.DEFAULT, connectTimeout, testTimeout);MySQLConnectionFactory factory = new MySQLConnectionFactory(configuration);POOL = new ConnectionPool<MySQLConnection>(factory, new PoolConfiguration(1000, 4, 1000, 4000), Main.system.dispatcher());
}private static interface PersistenceComplete {void apply(Throwable failure);
}

传递给persistSales(...)的回调在下一个清单中显示。 下面的代码与上一篇文章中显示的原始代码几乎没有什么不同,只是现在它的样式是异步的。 一旦所有销售都持续存在,就会调用该方法,然后回调才会在下面的第14行上通过其事件侦听器向参与者发送一条消息。 在加载大量新的购买和销售订单之后,该消息通常位于收件箱的后面。 这些消息中的每一个都会被处理,从而导致在重新开始交易之前,使用新订单更新交易引擎模型。

persistSales(sales, t -> {if(t != null){LOGGER.error("failed to persist sales: " + sales, t);}else{LOGGER.info("persisting completed, notifying involved parties...");sales.stream().forEach(sale -> {if (sale.getBuyer().listener != null)sale.getBuyer().listener.onEvent(EventType.PURCHASE, sale);if (sale.getSeller().listener != null)sale.getSeller().listener.onEvent(EventType.SALE, sale);});...}listener.onEvent(EventType.STOPPED, null);
});

最终的代码清单是对Node.js解决方案的修改,该修改使它也可以并行保持销售,而不是像上一篇文章中那样一个接一个地保持销售。

function persistSales(sales, callback){if(sales.length === 0 || process.env.skipPersistence) {callback(); //nothing to do, so continue immediately}else{resources.dbConnection(function(err, connection) {if(err) callback(err); else {logger.info('preparing to persist ' + sales.length + ' sales');var count = sales.length;_.each(sales, function(sale){ //save them in parallelconnection.query('INSERT INTO SALES (BUYER_NAME, SELLER_NAME, PRODUCT_ID, PRICE, QUANTITY, PO_ID, SO_ID) values (?, ?, ?, ?, ?, ?, ?)',[sale.buyer.name, sale.seller.name, sale.productId, sale.price, sale.quantity, sale.po.id, sale.so.id],function(err, rows, fields) {if(err) callback(err); else {sale.id = rows.insertId;count--;if(count == 0){logger.info('persisted all sales');connection.release();callback();}}});});}});}
}

第5行从池中获取一个连接,并且相同的连接“并行”用于所有销售,并在最后一次销售持续后才在第19行中释放,即返回到池中。

因此,再次通过一些负载测试比较解决方案的时间到了。 这次,我选择查看以下三个解决方案中的每一个可以达到的最大销售率:

  • 情况1 –此处介绍的解决方案,即Spray + Akka +异步Mysql驱动程序,
  • 情况2 –修改后的Node.js解决方案使用并行持久性,
  • 情况3 –原始的Tomcat非阻塞连接器,但是具有同步持久性。

这些案例是使用上一篇文章中的硬件运行的,交易引擎运行在快速硬件上,而数据库运行在慢速硬件上,因为这是显示阻塞I / O如何导致性能问题的最佳设置。 对于每种情况,我可以在调整时调整三个变量。 这些曾经是:

  • 交易引擎(作为参与者或子进程)的数量,
  • 客户端调用服务器之间等待的时间,
  • 并发客户端数。

后两个基本上调整了每秒的请求数,因为连接没有保持打开状态以等待交易结果(请参阅上一篇文章)。 结果如下,最佳性能以粗体显示。

情况1 – Spray + Akka +异步Mysql驱动程序
#交易引擎 两次通话之间的客户等待时间 并发客户 每分钟销量 大约 交易硬件上的CPU
8 100毫秒 60 42,810 25-35%
8 80毫秒 70 62,392 25-35%
8 60毫秒 80 75,600 30-40%
8 40毫秒 90 59,217 30-50%
10 60毫秒 80 太多的数据库连接问题
5 60毫秒 60 67,398 25-35%
6 60毫秒 80 79,536 25-35%

案例2 –具有并行持久性的Node.js
#交易引擎 两次通话之间的客户等待时间 并发客户 每分钟销量 大约 交易硬件上的CPU
8 200毫秒 30 6,684 40-50%
8 100毫秒 60 开始落后
8 100毫秒 40 17,058 25-35%
8 100毫秒 50 开始落后
12 100毫秒 50 20,808 45-60%
16 100毫秒 60 24,960 45-65%
20 100毫秒 80 32,718 45-70%
25 60毫秒 80 51,234 75-85%
30 50毫秒 80 22,026 75-85%
25 10毫秒 70 17,604 75-90%

情况3 – Tomcat 8 NIO,具有同步阻止持久性
#交易引擎 两次通话之间的客户等待时间 并发客户 每分钟销量 大约 交易硬件上的CPU
4 200毫秒 30 9,586 5%
4 150毫秒 30 10,221 5%
8 200毫秒 30 9,510 5%

结果表明,将NIO连接器用螺栓固定在Tomcat上并认为您没有阻塞并且性能很危险,因为与Akka解决方案相比,该解决方案的表现差了近8倍。 结果还表明,通过使用非阻塞库并用Java编写非阻塞解决方案,与Node.js相比,可以创建性能卓越的解决方案。 Java解决方案不仅具有大约50%的吞吐量,而且使用的CPU不到一半。

非常重要:请注意,这是特定于此处使用的算法以及我的体系结构,设计和实现的结果。 它还依赖于使用“非标准” Java库,实际上,我使用的Mysql库缺少功能,例如,从insert结果中读取生成的主键。 在得出关于Java,Scala和Node.js的相对性能的结论之前,请针对您的用例做自己的实验!

比较交易引擎数量变化时的一个值得注意的点:在Node.js中,它直接控制子进程的数量,类似于线程的数量; 在Akka解决方案中,它对系统中的线程数量没有任何影响–该数量保持不变! 在Akka解决方案中,更改参与者的数量会影响其收件箱中消息的数量。

有关此视频的详细信息,请参见有关Akka和Spray的使用。 请花时间也快速阅读有关React式宣言 。 此处介绍的Akka解决方案是React性的,因为它具有响应性(这三种情况中的吞吐量都最高),有弹性(Akka提供了处理故障的简便方法,尽管这里没有必要),有弹性(它是自动扩展的,因为Akka管理线程池)它在执行上下文中的大小,并且由于Akka提供了参与者的透明位置而扩大了规模,并且它是消息驱动的(由于使用了参与者模型)。

[1]这里使用的Mysql库不需要关闭连接并返回到池,例如Apache数据库池 。

这样做实际上会引起问题!

我进行的负载测试证明,将其保持打开状态不会造成任何问题。

翻译自: https://www.javacodegeeks.com/2015/01/a-reactive-and-performant-spray-akka-solution-to-playing-with-concurrency-and-performance-in-java-and-node-js.html

react性能优化方案

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

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

相关文章

linux 查看日志_干货 | 名企高频考点之谈谈Linux日志查看方式都有哪些

点击蓝字关注我哦以下是本期干货视频视频后还附有文字版本哦▼《名企高频考点-谈谈Linux日志查看方式都有哪些》▼ps&#xff1a;请在WiFi环境下打开&#xff0c;如果有钱任性请随意0.概述在我们面试各大公司的时候&#xff0c;关于Linux往往最容易问到的问题之一就是Linux指令…

vsm java_java – 我尝试使用JAXB将对象编组到xml文件中时,错误为“缺少@XmlRootElement注释”...

我是刚刚开始使用JAXB的人,所有我需要的是将对象写入xml并在某些时候将其读回java这是我的班级&#xff1a;public class VSM implements java.io.Externalizable{ArrayList termList; //Term DictionaryArrayList queryTermList; //Query listArrayList> docLists;ArrayLis…

jvm7 jvm8_自我修复的JVM

jvm7 jvm8这篇帖子是关于一个应用程序的示例&#xff0c;其中解决每个IT问题的第一个解决方案-“您是否尝试过将其关闭并重新打开”-可能适得其反&#xff0c;弊大于利。 我们不需要关闭电源&#xff0c;而是拥有可以自愈的应用程序&#xff1a;它在一开始就失败了&#xff0c…

实例讲解C语言的位运算

C语言位运算有6种&#xff1a; &&#xff0c; | , ^(异或)&#xff0c; <<(左移)&#xff0c;>>(右移)。注意&#xff1a;参与位运算的元素必须是int型或者char型&#xff0c;以补码形式出现。1.按位与&&运算常应用于&#xff1a;迅速清零保留指定位判…

python3解释器执行not 1 and 1_编程语言的分类,python解释器多版本共存.执行python的两种方式,变量,用户与程序交互...

一、编程语言的分类&#xff1f;机器语言&#xff1a;直接使用二进制指令编程&#xff0c;直接操作硬件&#xff0c;必须考虑硬件细节。汇编语言&#xff1a;用简写的英文标识符取代二进制去编写程序&#xff0c;直接操作硬件&#xff0c;必须考虑硬件细节。高级语言&#xff1…

java字节码执行原理_《Java 底层原理》Java 字节码详解

前言我们在开发中会遇到一些Java的执行超出我们的想象&#xff0c;但是又不知道他为什么会这样执行&#xff0c;这个时候我们就需要能够知道他编译后Class文件是什么样子的&#xff0c;并且理解字节码的含义。Java字节码的原理进制class文件就是字节码文件&#xff0c;直接是打…

C语言学习笔记--位运算

这一节主要说的是位运算&#xff0c;计算机中的执行速度&#xff1a;位运算 > 加减 > 乘除 > 求余位运算就是将数字转换成二进制后进行运算&#xff0c;之后再将数字转换成原来的进制与运算&#xff1a;当两个数相与时&#xff0c;只有都为l的时候结果才为1&#xff0…

openshift学习_在OpenShift上将JMS与JBoss A-MQ结合使用。 学习了有关远程客户端和加密的经验。...

openshift学习OpenShift是“红帽开发的开放式混合云应用程序平台”。 它具有不同的风格&#xff0c;对于大多数您想做的事情&#xff0c;最有趣的部分是公共云应用程序开发和托管平台“ OpenShift Online ”。 您可以轻松地尝试一下&#xff0c;因为在云中使用OpenShift Online…

mathtype运行时错误48_在office中无法使用MathType该怎么办?

想必大家都遇到过在office中无法使用MathType的情况&#xff0c;那么遇到这种情况的话大家应该怎么来解决呢&#xff1f;首先这样的现象一般为&#xff1a;word或者ppt中没有mathtype选项&#xff0c;或者选项打开提示文件未找到&#xff1a;MathPage.WLL。错误提示或者甚至运行…

谈谈C语言中的杂项运算符

在C语言中&#xff0c;还有一些重要的运算符&#xff0c;例如&#xff1a;sizeof()、&、* 、 ?: 。我们把上述的这些运算符归为杂项运算符&#xff0c;下面我将详细介绍这些杂项运算符。下面的表格列出了 C 语言支持的所有杂项运算符&#xff1a;运算符解释例子sizeof()返…

java集合的添加方法_深入理解java集合框架之---------Arraylist集合 -----添加方法

Arraylist集合 -----添加方法1、add(E e) 向集合中添加元素/*** 检查数组容量是否够用* param minCapacity*/public void ensureCapacity(int minCapacity){modCount;int oldCapacity elementData.length;if(minCapacity > oldCapacity){Object oldData[] elementData;int…

jenkins java_具有WildFly,Arquillian,Jenkins和OpenShift的Java EE 7部署管道

jenkins java技术提示&#xff03;54展示了如何Arquillianate&#xff08;Arquillianize&#xff1f;&#xff09;一个现有的Java EE项目并在WildFly在已知主机和端口上运行的远程模式下运行这些测试。 技术提示&#xff03;55展示了当WildFly在OpenShift中运行时如何运行这些测…

matplotlib 折线图_漂亮图表也可信手拈来,一文学会用Python绘制堆积折线图

今天咱们还是接着上次的话题&#xff0c;继续和大家聊聊关于Python绘图相关的东东哦&#xff0c;上次已经和大家讨论完了如何给自己所绘制的图表中添加装饰线以及修改装饰线密度的方法&#xff0c;今天呢&#xff0c;咱们再聊点的新的东东哦&#xff0c;还是和大家继续深耕Pyth…

C语言 | 赋值与运算符

本章以鸡兔同笼为例&#xff0c;讲解赋值语句和一些简单的运算符。相关知识点&#xff1a;scanf(" %d " , &i ); 输入函数&#xff0c;表示输入一个整数&#xff08;%d&#xff09;&#xff0c;赋值给 i&#xff08;&i&#xff09;C语言中加法运算符为 减法…

菜鸟学java要多久_菜鸟学java,根本停不下来!

位运算符&: 两个2进制的操作数,同一位数的两个数如果有一个为0结果就为0,两个都为1才是1.| : 两个2进制的操作数,同一位数的两个数如果有一个为1,两个都为0才是0.^ : 两个2进制的操作数,同一位数的两个数如果相同为0,不同为1.位移运算符<< 左移:把第一个二进制的操作…

响应式多级菜单 侧边菜单栏_使用纯HTML和OmniFaces构建动态响应的多级菜单

响应式多级菜单 侧边菜单栏最近&#xff0c;我不得不使用JSF 2.2创建一个响应式多级菜单。 要求&#xff1a;菜单应&#xff1a; 从后端使用动态结构创建 React灵敏&#xff0c;例如对桌面和移动设备友好 有带有导航链接的子菜单项 支持触摸事件 支持键盘辅助功能 PrimeF…

python列表中随机两个_随机化两个列表并在python中维护顺序

随机化两个列表并在python中维护顺序说我有两个简单的清单&#xff0c;a [Spears, "Adele", "NDubz", "Nicole", "Cristina"]b [1,2,3,4,5]len(a) len(b)我想做的是将a和a随机化&#xff0c;但要保持顺序。 因此&#xff0c;类似&a…

C语言中的头文件

头文件是扩展名为 .h 的文件&#xff0c;包含了 C 函数声明和宏定义&#xff0c;被多个源文件中引用共享。有两种类型的头文件&#xff1a;程序员编写的头文件和编译器自带的头文件。在程序中要使用头文件&#xff0c;需要使用 C 预处理指令 #include 来引用它。前面我们已经看…

ceph-rest-api_快速检查REST API是否有效的方法-从清单文件中获取详细信息

ceph-rest-api在某些情况下&#xff0c;您可能想快速验证部署在开发&#xff0c;测试或生产环境中的REST API是否完全可以访问。 一种常见的实现方法是构建通用资源&#xff0c;该资源可提供例如已部署API的版本。 您可以手动触发对此资源的请求&#xff0c;或者更好的是&#…

set trans 必须是事务处理的第一个语句_MySQL中特别实用的几种SQL语句送给大家

在写SQL时&#xff0c;经常灵活运用一些SQL语句编写的技巧&#xff0c;可以大大简化程序逻辑。减少程序与数据库的交互次数&#xff0c;有利于数据库高可用性&#xff0c;同时也能显得你的SQL很牛B&#xff0c;让同事们眼前一亮。实用的SQL1.插入或替换如果我们想插入一条新记录…