当前位置: 首页 > news >正文

RestTemplate使用HttpClient连接池

文章目录

  • RestTemplate使用HttpClient连接池
    • ClientHttpRequestFactory
    • SimpleClientHttpRequestFactory
      • SimpleClientHttpRequestFactory 设置超时时间
      • HttpURLConnection的缺点
    • HttpComponentsClientHttpRequestFactory
      • PoolingHttpClientConnectionManager配置连接池
    • HttpClient总结图
    • 参考

RestTemplate使用HttpClient连接池

ClientHttpRequestFactory

@FunctionalInterface
public interface ClientHttpRequestFactory {/*** Create a new {@link ClientHttpRequest} for the specified URI and HTTP method.* <p>The returned request can be written to, and then executed by calling* {@link ClientHttpRequest#execute()}.* @param uri the URI to create a request for* @param httpMethod the HTTP method to execute* @return the created request* @throws IOException in case of I/O errors*/ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException;}

ClientHttpRequestFactory是个函数式接口,用于根据URI和HttpMethod创建出一个ClientHttpRequest来发送请求。

/*** Represents a client-side HTTP request.* Created via an implementation of the {@link ClientHttpRequestFactory}.** <p>A {@code ClientHttpRequest} can be {@linkplain #execute() executed},* receiving a {@link ClientHttpResponse} which can be read from.** @author Arjen Poutsma* @since 3.0* @see ClientHttpRequestFactory#createRequest(java.net.URI, HttpMethod)*/
public interface ClientHttpRequest extends HttpRequest, HttpOutputMessage {/*** Execute this request, resulting in a {@link ClientHttpResponse} that can be read.* @return the response result of the execution* @throws IOException in case of I/O errors*/ClientHttpResponse execute() throws IOException;}

ClientHttpRequest则代表客户端的HTTP请求

在这里插入图片描述

ClientHttpRequest底下的实现有HttpClient,OkHttp3,以及Java jdk内置的HttpUrlConnection

SimpleClientHttpRequestFactory

RestTemplate默认使用SimpleClientHttpRequestFactory,是Spring内置默认的实现

在这里插入图片描述

SimpleClientHttpRequestFactory创建出的ClientHttpRequest是使用Java jdk内置的HttpUrlConnection实现的。

在这里插入图片描述

SimpleClientHttpRequestFactory 设置超时时间

特别需要注意的是当我们直接new RestTemplate的时候,底层默认使用的SimpleClientHttpRequestFactory是没有设置超时时间的,而Java jdk内置的HttpUrlConnection,若readTimeout和connectTimeout没有设置,那请求是没有超时时间的,会导致请求一直pending住。

在这里插入图片描述

在这里插入图片描述

所以我们使用RestTemplate的时候务必设置上超时时间

@Beanpublic RestTemplate restTemplate(){RestTemplate restTemplate = new RestTemplate();SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();simpleClientHttpRequestFactory.setConnectTimeout(10000);simpleClientHttpRequestFactory.setReadTimeout(30000);restTemplate.setRequestFactory(simpleClientHttpRequestFactory);return restTemplate;}

HttpURLConnection的缺点

HttpURLConnection是JDK内置的,所以它除了封装的比较简单之外还存在性能上的问题。

因为他在每一次创建请求的时候都会建立一个新的连接,所以没办法复用连接。而且如果通信异常会导致连接不被回收,进而导致创建的连接越来越多,最终导致服务卡死

在这里插入图片描述

在这里插入图片描述

HttpComponentsClientHttpRequestFactory

上面的HttpURLConnection的缺点就是我们为什么是需要使用HttpClient连接池。为了就是更好复用连接。

为什么要用连接池?
因为使用它可以有效降低延迟和系统开销。如果不采用连接池,每当我们发起http请求时,都需要重新发起Tcp三次握手建立链接,请求结束时还需要四次挥手释放链接。而Tcp链接的建立和释放是有时间和系统开销的。另外每次发起请求时,需要分配一个端口号,请求完毕后在进行回收。使用链接池则可以复用已经建立好的链接,一定程度的避免了建立和释放链接的时间开销。

在HttpClient 4.3以后增加了PoolingHttpClientConnectionManager连接池来管理持有连接,同一条TCP链路上,连接是可以复用的。HttpClient通过连接池的方式进行连接持久化(所以它这个连接池其实是tcp的连接池。它里面有一个很重要的概念:Route的概念,代表一条线路。比如baidu.com是一个route,163.com是一个route…)。
连接池:可能是http请求,也可能是https请求
加入池话技术,就不用每次发起请求都新建一个连接(每次连接握手三次,效率太低)
参考:https://blog.51cto.com/u_3631118/3121677

使用HttpClient我们首先需要引入依赖

<dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.13</version>
</dependency>

然后我们只需要把之前的SimpleClientHttpRequestFactory改成HttpComponentsClientHttpRequestFactory

@Beanpublic RestTemplate restTemplate(){RestTemplate restTemplate = new RestTemplate();HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();restTemplate.setRequestFactory(clientHttpRequestFactory);return restTemplate;}

PoolingHttpClientConnectionManager配置连接池

配置连接池,我们就需要用到PoolingHttpClientConnectionManager

PoolingHttpClientConnectionManager的作用如下:

ClientConnectionPoolManager maintains a pool of HttpClientConnections and is able to service connection requests from multiple execution threads. Connections are pooled on a per route basis. A request for a route which already the manager has persistent connections for available in the pool will be services by leasing a connection from the pool rather than creating a brand new connection.
参考: https://hc.apache.org/httpcomponents-client-4.5.x/current/httpclient/apidocs/

大概意思就是PoolingHttpClientConnectionManager使用来维护一个连接池,能够为来自多个执行线程的连接请求提供服务。连接池是基于每个路由的(比如baidu.com是一个路由,163.com是一个路由)。对路由的请求,如果连接池中有可用的持久连接,则将通过将复用连接池中的连接,而不是创建全新的连接。

那我们在如何给RestTemplate设置HttpClient的连接池呢?

  @Beanpublic RestTemplate restTemplate(){RestTemplate restTemplate = new RestTemplate();restTemplate.setRequestFactory(httpComponentsClientHttpRequestFactory());return restTemplate;}private HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory() {HttpComponentsClientHttpRequestFactory requestFactory =new HttpComponentsClientHttpRequestFactory(httpClientBuilder().build());return requestFactory;}private HttpClientBuilder httpClientBuilder() {return HttpClients.custom().setConnectionManager(poolingConnectionManager());}private PoolingHttpClientConnectionManager poolingConnectionManager() {PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();return connectionManager;}

我们首先需要创建一个HttpClientBuilder,然后我们需要在创建我们的PoolingHttpClientConnectionManager,然后为HttpClientBuilder调用setConnectionManager设置连接管理器。最后我们再用这个HttpClientBuilder来初始化我们的HttpComponentsClientHttpRequestFactory

接下来我们的核心重点还是在PoolingHttpClientConnectionManager

我们可以看看PoolingHttpClientConnectionManager的默认构造方法

在这里插入图片描述

有两个很显眼的默认参数值分别是2和20,且这两个值分别对应HttpClientBuilder的两个配置参数。官方给出了解释

ClientConnectionPoolManager maintains a maximum limit of connection on a per route basis and in total. Per default this implementation will create no more than than 2 concurrent connections per given route and no more 20 connections in total.

大概意思就是PoolingHttpClientConnectionManager在默认情况下,每个路由的并发连接最大是2个,全部路由总共最大是20个。

默认配置限制的太小了,所以我们一般需要根据自己需求进行配置,如下:

connectionManager.setMaxTotal(1000); //最大连接数
connectionManager.setDefaultMaxPerRoute(500); //每个路由(域名)最大连接数

顺便一提的是,在HttpClientBuilder中也可以设置这两个参数,分别是setMaxConnPerRoutesetMaxConnTotal。但是他们都会被PoolingHttpClientConnectionManager中设置的覆盖

在这里插入图片描述

接下来我们来看看超时的配置

我们可以通过HttpComponentsClientHttpRequestFactory中的三个参数来设置超时

requestFactory.setConnectTimeout(CONNECT_TIMEOUT);
requestFactory.setConnectionRequestTimeout(CONNECT_TIMEOUT);
requestFactory.setReadTimeout(TIMEOUT);

这三个参数跟我们设置RequestConfig中是等价的。

我们可以在HttpClientBuilder中利用setDefaultRequestConfig方法设置RequestConfig。在RequestConfig一样有三个参数来配置超时。

public RequestConfig requestConfig() {return RequestConfig.custom().setConnectionRequestTimeout(CONNECT_TIMEOUT).setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(TIMEOUT).build();}

我们先来介绍RequestConfig中的这三个配置

  • setConnectionRequestTimeout: 从连接管理器请求连接时使用的超时时间(以毫秒为单位)
  • setConnectTimeout:确定连接建立之前的超时时间(以毫秒为单位)。也就是客户端发起TCP连接请求的超时时间,一般也就是TCP三次握手的时间
  • setSocketTimeout:客户端等待服务端返回数据的超时时间

这三个值默认都是-1,也就是没有超时的限制。

HttpComponentsClientHttpRequestFactory中的三个超时配置其实内部也是在配置RequestConfig的超时配置。

/*** Set the connection timeout for the underlying {@link RequestConfig}.* A timeout value of 0 specifies an infinite timeout.* <p>Additional properties can be configured by specifying a* {@link RequestConfig} instance on a custom {@link HttpClient}.* <p>This options does not affect connection timeouts for SSL* handshakes or CONNECT requests; for that, it is required to* use the {@link org.apache.http.config.SocketConfig} on the* {@link HttpClient} itself.* @param timeout the timeout value in milliseconds* @see RequestConfig#getConnectTimeout()* @see org.apache.http.config.SocketConfig#getSoTimeout*/public void setConnectTimeout(int timeout) {Assert.isTrue(timeout >= 0, "Timeout must be a non-negative value");this.requestConfig = requestConfigBuilder().setConnectTimeout(timeout).build();}/*** Set the timeout in milliseconds used when requesting a connection* from the connection manager using the underlying {@link RequestConfig}.* A timeout value of 0 specifies an infinite timeout.* <p>Additional properties can be configured by specifying a* {@link RequestConfig} instance on a custom {@link HttpClient}.* @param connectionRequestTimeout the timeout value to request a connection in milliseconds* @see RequestConfig#getConnectionRequestTimeout()*/public void setConnectionRequestTimeout(int connectionRequestTimeout) {this.requestConfig = requestConfigBuilder().setConnectionRequestTimeout(connectionRequestTimeout).build();}/*** Set the socket read timeout for the underlying {@link RequestConfig}.* A timeout value of 0 specifies an infinite timeout.* <p>Additional properties can be configured by specifying a* {@link RequestConfig} instance on a custom {@link HttpClient}.* @param timeout the timeout value in milliseconds* @see RequestConfig#getSocketTimeout()*/public void setReadTimeout(int timeout) {Assert.isTrue(timeout >= 0, "Timeout must be a non-negative value");this.requestConfig = requestConfigBuilder().setSocketTimeout(timeout).build();}

从查看源码可以看出来HttpComponentsClientHttpRequestFactorysetConnectTimeout等价于RequestConfig中的setConnectTimeout,HttpComponentsClientHttpRequestFactorysetConnectionRequestTimeout等价于RequestConfig中的setConnectionRequestTimeout,HttpComponentsClientHttpRequestFactorysetReadTimeout等价于RequestConfig中的setSocketTimeout

但从源码上看,他们本质上设置的不是同一个RequestConfig,而是在createRequest操作的时候会进行一个merge的操作。

/*** Merge the given {@link HttpClient}-level {@link RequestConfig} with* the factory-level {@link RequestConfig}, if necessary.* @param clientConfig the config held by the current* @return the merged request config* @since 4.2*/protected RequestConfig mergeRequestConfig(RequestConfig clientConfig) {if (this.requestConfig == null) {  // nothing to mergereturn clientConfig;}RequestConfig.Builder builder = RequestConfig.copy(clientConfig);int connectTimeout = this.requestConfig.getConnectTimeout();if (connectTimeout >= 0) {builder.setConnectTimeout(connectTimeout);}int connectionRequestTimeout = this.requestConfig.getConnectionRequestTimeout();if (connectionRequestTimeout >= 0) {builder.setConnectionRequestTimeout(connectionRequestTimeout);}int socketTimeout = this.requestConfig.getSocketTimeout();if (socketTimeout >= 0) {builder.setSocketTimeout(socketTimeout);}return builder.build();}

从源码的注释也可以看出来,他会把HttpComponentsClientHttpRequestFactory中的RequestConfig和我们在HttpClientBuilder中设置的RequestConfig进行一个合并。

那我们继续来关注PoolingHttpClientConnectionManager, 我们可以发现PoolingHttpClientConnectionManager有如下的构造方法

public PoolingHttpClientConnectionManager(long timeToLive, TimeUnit timeUnit)

那这个timeToLive,也就是我们常说的TTL是什么意思呢?
我们可以看官网的解释如下:

Total time to live (TTL) set at construction time defines maximum life span of persistent connections regardless of their expiration setting. No persistent connection will be re-used past its TTL value.

大概意思就是在构造时设置的持久链接的存活时间(TTL),它定义了持久连接的最大使用时间。超过其TTL值的连接不会再被复用。

   /*** Creates new {@code PoolEntry} instance.** @param id unique identifier of the pool entry. May be {@code null}.* @param route route to the opposite endpoint.* @param conn the connection.* @param timeToLive maximum time to live. May be zero if the connection*   does not have an expiry deadline.* @param timeUnit time unit.*/public PoolEntry(final String id, final T route, final C conn,final long timeToLive, final TimeUnit timeUnit) {super();Args.notNull(route, "Route");Args.notNull(conn, "Connection");Args.notNull(timeUnit, "Time unit");this.id = id;this.route = route;this.conn = conn;this.created = System.currentTimeMillis();this.updated = this.created;if (timeToLive > 0) {final long deadline = this.created + timeUnit.toMillis(timeToLive);// If the above overflows then default to Long.MAX_VALUEthis.validityDeadline = deadline > 0 ? deadline : Long.MAX_VALUE;} else {this.validityDeadline = Long.MAX_VALUE;}this.expiry = this.validityDeadline;}

从上面代码我们可以看出来当我们设置了TTL,创建PoolEntry的时候就会设置一个expiry过期时间。超过过期时间的连接就会标志为过期的。

在这里插入图片描述

所以我们设置了TTL,就相当于设置了连接最大的可用时间,超过了这个可用时间的连接,就会从池中剔除,变为不可重用。

除此之外HttpClientBuilder中也能设置TTL

   /*** Sets maximum time to live for persistent connections* <p>* Please note this value can be overridden by the {@link #setConnectionManager(*   org.apache.http.conn.HttpClientConnectionManager)} method.* </p>** @since 4.4*/public final HttpClientBuilder setConnectionTimeToLive(final long connTimeToLive, final TimeUnit connTimeToLiveTimeUnit) {this.connTimeToLive = connTimeToLive;this.connTimeToLiveTimeUnit = connTimeToLiveTimeUnit;return this;}

方法的注释上也说明了,这个设置会被PoolingHttpClientConnectionManager中设置的TTL覆盖。

同时官网还提到了

The handling of stale connections was changed in version 4.4. Previously, the code would check every connection by default before re-using it. The code now only checks the connection if the elapsed time since the last use of the connection exceeds the timeout that has been set. The default timeout is set to 2000ms

大概意思就是在4.4版中更改了对不可重用连接的处理。4.4之前在重用每个连接之前默认检查每个连接是否已经可重用。4.4之后是自上次使用连接以来所经过的时间超过已设置的连接不活动时间(默认连接不活动时间设置为2000ms),才检查连接。如果发现连接不可用,则从连接池剔除,在重新获取新的链接。

上面getPoolEntryBlocking的代码中,我们不是已经判断了连接是否过期,还有连接是否关闭了吗?为什么还需要判断连接是否可用?

在这里插入图片描述

我的想法是,连接过期或者是连接是否关闭并不代表连接还是能重用的,有可能连接是打开状态的,但是连接的时候存在一些问题(这种概率可能很小),所以需要作进一步的可重用检测

在这里插入图片描述

在这里插入图片描述

setValidateAfterInactivity使用来定义以毫秒为单位的连接不活动时间,在此之后,在将持久连接租给使用者之前必须重新验证。如果ValidateAfterInactivity的值小于0则表示禁用连接验证。

从上面的源码我们可以看出来,默认配置的检查时间为2s。然后我们从代码上可以看出来,再每次去创建连接的时候,会从连接池中进行连接的租赁,在去连接池获取连接的时候,会判validateAfterInactivity + 当前获取的连接上次最后的使用时间是否小于当前时间,如果小于则需要检查连接是否可用。如果检查到连接不可用,则会把当前连接从连接池中剔除,然后重新获取新的连接。

我们可以看到校验方法最后调用isStale方法

在这里插入图片描述

 /*** Checks whether this connection has gone down.* Network connections may get closed during some time of inactivity* for several reasons. The next time a read is attempted on such a* connection it will throw an IOException.* This method tries to alleviate this inconvenience by trying to* find out if a connection is still usable. Implementations may do* that by attempting a read with a very small timeout. Thus this* method may block for a small amount of time before returning a result.* It is therefore an <i>expensive</i> operation.** @return  {@code true} if attempts to use this connection are*          likely to succeed, or {@code false} if they are likely*          to fail and this connection should be closed*/boolean isStale();

isStale()方法是会阻塞一小段时间的,所以为什么在4.4版本之后不会每次都检查,而是超过连接不活动时间之后才会进行检查。

最后我们再来看两个配置,这两个配置能够帮助我们定期清理连接。

这两个配置都是在HttpClientBuilder中进行配置。

  • evictExpiredConnections:定时清理过期连接的开关,默认关闭,建议打开

  • evictIdleConnections:定时清理闲置连接的开关,默认关闭, 需要指定时间,建议打开

这两个分别是什么意思呢?

定时清理过期连接

其实就是清理超过TTL时间的链接,跟上面getPoolEntryBlocking代码中获取连接中会检查过期连接是一样的。我个人想法就是一个是主动清理,一个是获取连接的时候才会清理。而且一个是主动清理池中全部过期的,而另一个只是获取到池中的连接才进行清理,并不是清理全部。

定时清理闲置连接

先说 keep-alive 机制。每个 TCP 连接都要经过三次握手建立连接后才能发送数据,要经过四次挥手才能断开连接,如果每个 TCP 连接在服务端返回后都立马断开,则发起多个 HTTP 请求就要多次创建和断开 TCP,这在请求很多的情况下无疑是很耗性能的。如果在服务端返回后不立即断开 TCP 链接,而是复用这条连接进行下一次的 Http 请求,则可以省略了很多创建 断开 TCP 的开销,性能上无疑会有很大提升。虽然 keep-alive 省去了很多不必要的握手/挥手操作,但由于连接长期存活,如果没有请求的话也会浪费系统资源。所以定时清理闲置连接就是主动去清理超过指定时间都没有被使用过的连接。

我们直接上源代码来看看

在这里插入图片描述

当我们设置了evictExpiredConnections或者设置了evictIdleConnections, 就会构造一个IdleConnectionEvictor空闲连接清除器。如果没有指定maxIdleTime的话,但是有设置evictExpiredConnections的话,默认是10秒。

在这里插入图片描述

IdleConnectionEvictor中会启动一个线程,然后在指定的maxIdleTime时间之后调用connectionManager.closeExpiredConnections();connectionManager.closeIdleConnections(maxIdleTimeMs, TimeUnit.MILLISECONDS);进行连接清理。

我们先来看connectionManager.closeExpiredConnections();方法

 /*** Closes all expired connections in the pool.* <p>* Open connections in the pool that have not been used for* the timespan defined when the connection was released will be closed.* Currently allocated connections are not subject to this method.* Times will be checked with milliseconds precision.* </p>*/void closeExpiredConnections();
@Overridepublic void closeExpiredConnections() {this.log.debug("Closing expired connections");this.pool.closeExpired();}
 /*** Closes expired connections and evicts them from the pool.*/public void closeExpired() {final long now = System.currentTimeMillis();enumAvailable(new PoolEntryCallback<T, C>() {@Overridepublic void process(final PoolEntry<T, C> entry) {if (entry.isExpired(now)) { //超过TTL时间的会标记为过期,对于过期的连接则会进行清理entry.close();}}});}

从上面的代码可以看出来,closeExpiredConnections方法会清理池中全部的过期连接,判断过期则会依据我们设置的TTL

然后我们来看connectionManager.closeIdleConnections(maxIdleTimeMs, TimeUnit.MILLISECONDS);方法

/*** Closes idle connections in the pool.* <p>* Open connections in the pool that have not been used for the* timespan given by the argument will be closed.* Currently allocated connections are not subject to this method.* Times will be checked with milliseconds precision* </p>* <p>* All expired connections will also be closed.* </p>** @param idletime  the idle time of connections to be closed* @param timeUnit     the unit for the {@code idletime}** @see #closeExpiredConnections()*/void closeIdleConnections(long idletime, TimeUnit timeUnit);
@Overridepublic void closeIdleConnections(final long idleTimeout, final TimeUnit timeUnit) {if (this.log.isDebugEnabled()) {this.log.debug("Closing connections idle longer than " + idleTimeout + " " + timeUnit);}this.pool.closeIdle(idleTimeout, timeUnit);}
/*** Closes connections that have been idle longer than the given period* of time and evicts them from the pool.** @param idletime maximum idle time.* @param timeUnit time unit.*/public void closeIdle(final long idletime, final TimeUnit timeUnit) {Args.notNull(timeUnit, "Time unit");long time = timeUnit.toMillis(idletime);if (time < 0) {time = 0;}final long deadline = System.currentTimeMillis() - time;enumAvailable(new PoolEntryCallback<T, C>() {@Overridepublic void process(final PoolEntry<T, C> entry) {if (entry.getUpdated() <= deadline) {entry.close();}}});}

从源码看出来,closeIdleConnections会清理池中所有的空闲连接。只要连接的上次使用时间超过了我们设置的maxIdleTime则属于空闲连接,需要清除掉。

HttpClient总结图

在这里插入图片描述

参考

RestTemplate组件:ClientHttpRequestFactory、ClientHttpRequestInterceptor、ResponseExtractor

HttpClient使用连接池

使用HttpClient的正确姿势

RestTemplate未使用线程池问题

傻傻分不清的TCP keepalive和HTTP keepalive

【348期】高并发场景下的 httpClient 使用优化

HttpClient 在vivo内销浏览器的高并发实践优化

httpClient连接池管理,你用对了?

简单粗暴的RestTemplate

Spring RestTemplate 设置每次请求的 Timeout

可视化的分析Keep-Alive长连接

restTemplate超时时间引发的生产事故

HttpClient官网

Http 持久连接与 HttpClient 连接池

httpclient参数配置

HttpClient 专题

相关文章:

RestTemplate使用HttpClient连接池

文章目录RestTemplate使用HttpClient连接池ClientHttpRequestFactorySimpleClientHttpRequestFactorySimpleClientHttpRequestFactory 设置超时时间HttpURLConnection的缺点HttpComponentsClientHttpRequestFactoryPoolingHttpClientConnectionManager配置连接池HttpClient总结…...

Python 操作Redis

在 Python中我们使用 redis库来操作 Redis数据库。Redis数据库的使用命令这里就不介绍了。 需要安装 redis库。检查是否安装redis&#xff1a; pip redis 如果未安装&#xff0c;使用 pip命令安装 redis。 pip install redis #安装最新版本 一、Redis连接 Redis提供两个类 Re…...

CEC2020:鱼鹰优化算法(Osprey optimization algorithm,OOA)求解CEC2020(提供MATLAB代码

一、鱼鹰优化算法简介 鱼鹰优化算法&#xff08;Osprey optimization algorithm&#xff0c;OOA&#xff09;由Mohammad Dehghani 和 Pavel Trojovsk于2023年提出&#xff0c;其模拟鱼鹰的捕食行为。 鱼鹰是鹰形目、鹗科、鹗属的仅有的一种中型猛禽。雌雄相似。体长51-64厘米…...

词对齐 - MGIZA++

文章目录关于 MGIZAgiza-py安装 MGIZA命令说明mkclsd4normhmmnormplain2sntsnt2coocsnt2coocrmpsnt2plainsymalmgizageneral parameters:No. of iterations:parameter for various heuristics in GIZA for efficient training:parameters for describing the type and amount o…...

GUI 之 Tkinter编程

GUI 图形界面&#xff0c;Tkinter 是 Python 内置的 GUI 库&#xff0c;IDLE 就是 Tkinter 设计的。 1. Tkinter 之初体验 import tkinter as tkroot tk.Tk() # 创建一个窗口root.title(窗口标题)# 添加 label 组件 theLabel tk.Label(root, text文本内容) theLabel.p…...

【软件测试】性能测试面试题都问什么?面试官想要什么?回答惊险避坑......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 1、你认为不同角色关…...

后端开发基础能力以及就Java的主流开发框架介绍

前言&#xff1a;java语言开发转后端&#xff0c;必须了解后端主流的一些东西&#xff0c;共勉。 后端开发需要具备以下基础能力&#xff1a; 1.编程语言&#xff1a;熟练掌握至少一门编程语言&#xff0c;如Java、Python、Ruby、PHP、C#等。 2.数据结构和算法&#xff1a;具…...

H2数据库连接时用户密码错误:Wrong user name or password [28000-214] 28000/28000 (Help)

H2数据库连接时用户密码错误: 2023-03-03 08:25:07 database: wrong user or password; user: "SA" org.h2.message.DbException: Wrong user name or password [28000-214]出现的问题配置信息原因解决办法org.h2.message.DbException: Wrong user name or password …...

青岛诺凯达机械盛装亮相2023济南生物发酵展,3月与您相约

BIO CHINA生物发酵展&#xff0c;作为生物发酵产业一年一度行业盛会&#xff0c;由中国生物发酵产业协会主办&#xff0c;上海信世展览服务有限公司承办&#xff0c;2023第10届国际生物发酵展&#xff08;济南&#xff09;于2023年3月30-4月1日在山东国际会展中心&#xff08;济…...

【JAVA程序设计】【C00111】基于SSM的网上图书商城管理系统——有文档

基于SSM的网上图书商城管理系统——有文档项目简介项目获取开发环境项目技术运行截图项目简介 基于ssm框架开发的网上在线图书售卖商城项目&#xff0c;本项目分为三种权限&#xff1a;系统管理员、卖家、买家 管理员角色包含以下功能&#xff1a; 用户信息管理、权限管理、订…...

基于卷积神经网络CNN的三相故障识别

目录 背影 卷积神经网络CNN的原理 卷积神经网络CNN的定义 卷积神经网络CNN的神经元 卷积神经网络CNN的激活函数 卷积神经网络CNN的传递函数 卷积神经网络CNN手写体识别 基本结构 主要参数 MATALB代码 结果图 展望 背影 现在生活&#xff0c;为节能减排&#xff0c;减少电能损…...

Java工厂设计模式详解,大厂的Java抽象工厂模式分享!

我是好程序员-小源&#xff01;本期文章主要给大家分享&#xff1a;Java工厂设计模式。文中使用通俗易懂的案例&#xff0c;使你快速学习和轻松上手&#xff01;一、什么是Java抽象工厂模式1. Java抽象工厂是23种设计模式中创建型模式的一种&#xff0c;Java抽象工厂是由多个工…...

Git 企业级分支提交流程

Git 企业级分支提交流程 首先在本地分支hfdev上进行开发&#xff0c;开发后要经过测试。 如果测试通过了&#xff0c;那么久可以合并到本地分支develop&#xff0c;合并之后hfdev和development应该完全一样。 git add 文件 git commit -m ‘注释’ git checkout develop //切换…...

C/C++每日一练(20230303)

目录 1. 字符串相乘 2. 单词拆分 II 3. 串联所有单词的子串 1. 字符串相乘 给定两个以字符串形式表示的非负整数 num1 和 num2&#xff0c;返回 num1 和 num2 的乘积&#xff0c;它们的乘积也表示为字符串形式。 示例 1: 输入: num1 "2", num2 "3"…...

Python3-条件控制

Python3 条件控制 Python 条件语句是通过一条或多条语句的执行结果&#xff08;True 或者 False&#xff09;来决定执行的代码块。 可以通过下图来简单了解条件语句的执行过程: 代码执行过程&#xff1a; if 语句 Python中if语句的一般形式如下所示&#xff1a; if condi…...

KDZD地埋电缆故障测试仪

一、产品特性 ★电缆故障测试仪&#xff08;闪测仪&#xff09; &#xff08;1&#xff09;使用范围广&#xff1a;用于测量各种不同截面、不同介质的各种电力电缆、高频同轴电缆&#xff0c;市话电缆及两根以上均匀铺设的地埋电线等电缆高低阻、短路、开路、断线以及高阻泄漏…...

爆款升级!新系列南卡Neo最强旗舰杀到,业内首款无线充骨传导耳机!

中国专业骨传导耳机品牌NANK南卡于近日发布了全新南卡Neo骨传导运动耳机&#xff0c;打造一款佩戴最舒适、音质体验最好的骨传导耳机。推出第2代声学響科技技术&#xff0c;提供更优质的开放式骨传导听音体验&#xff0c;透过不一样的音质体验&#xff0c;打造更好的骨传导耳机…...

基于Spring Boot+Thymeleaf的在线投票系统

文章目录 项目介绍主要功能截图:后台登录注册个人信息展示投票数据显示首页展示对战匹配分数排行榜部分代码展示设计总结项目获取方式🍅 作者主页:Java韩立 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅…...

【每日一题Day135】LC1487保证文件名唯一 | 哈希表

保证文件名唯一【LC1487】 给你一个长度为 n 的字符串数组 names 。你将会在文件系统中创建 n 个文件夹&#xff1a;在第 i 分钟&#xff0c;新建名为 names[i] 的文件夹。 由于两个文件 不能 共享相同的文件名&#xff0c;因此如果新建文件夹使用的文件名已经被占用&#xff0…...

计算机系统的基本组成 第一节

一、计算机系统 计算机系统是指&#xff1a;电子数字通用、计算机系统 由硬件和软件两个子系统组成 硬件是保存和运行软件的物质基础 软件是指挥硬件完成预期功能的智力部分 重点&#xff1a; 计算机系统部件 五个 1、数据运算部件&#xff1a;完成对数据的运算处理功能…...

Scrapy爬虫框架入门

Scrapy是Python开发的一个非常流行的网络爬虫框架&#xff0c;可以用来抓取Web站点并从页面中提取结构化的数据&#xff0c;被广泛的用于数据挖掘、数据监测和自动化测试等领域。下图展示了Scrapy的基本架构&#xff0c;其中包含了主要组件和系统的数据处理流程&#xff08;图中…...

最新使用nvm控制node版本步骤

一、完全卸载已经安装的node、和环境变量 ①、打开控制面板的应用与功能&#xff0c;搜索node&#xff0c;点击卸载 ②、打开环境变量&#xff0c;将node相关的所有配置清除 ③、打开命令行工具&#xff0c;输入node-v&#xff0c;没有版本号则卸载成功 二、下载nvm安装包 ①…...

Linux内核4.14版本——drm框架分析(1)——drm简介

目录 1. DRM简介&#xff08;Direct Rendering Manager&#xff09; 1.1 DRM发展历史 1.2 DRM架构对比FB架构优势 1.3 DRM图形显示框架 1.4 DRM图形显示框架涉及元素 1.4.1 DRM Framebuffer 1.4.2 CRTC 1.4.3 Encoder 1.4.4 Connector 1.4.5 Bridge 1.4.6 Panel 1.4.…...

Google的一道经典面试题 - 767. 重构字符串

文章目录Google的一道经典面试题 - 767. 重构字符串767. 重构字符串1054. 距离相等的条形码结论Google的一道经典面试题 - 767. 重构字符串 767. 重构字符串 题目链接&#xff1a;767. 重构字符串 题目大意&#xff1a;给定一个字符串 s &#xff0c;检查是否能重新排布其中的…...

E8-公共选择框相关的表

起因 昨天同事和我说&#xff0c;要在一个表单里加一组可选项。于是我去了公共选择框维护。这时候才发了这么个问题&#xff0c;前几天我在本机的测试环境里做的流程&#xff0c;导入到我们的生产环境里&#xff0c;表单里所用到的共公选择框的选项都在&#xff0c;在表单里是…...

再学C语言41:变长数组(VLA)

处理二维数组的函数&#xff1a;数组的行可以在函数调用时传递&#xff0c;但是数组的列只能被预置在函数内部 示例代码&#xff1a; #define COLS 4 int sum(int arr[][COLS], int rows) {int r;int c;int temp 0;for(r 0; r < rows; r){for(c 0; c < COLS; c){tem…...

物联网WEB大屏数据可视化

最近了解WEB大屏显示。一般像嵌入式这类的&#xff0c;MQTT协议会走的多一些&#xff0c;走订阅和发布的策略&#xff0c;网上走了一圈之后&#xff0c;目前有几个实现方案。这里对比一下几个物联网协议&#xff0c;相对而言MQTT更合适物联网&#xff0c;其它几个协议不是干这个…...

新:DlhSoft Gantt Chart for WPF Crack

用于 Silverlight/WPF 4.3.48 的 DlhSoft 甘特图灯光库 改进甘特图、网络图和 PERT 图表组件的 PERT 关键路径算法。2023 年 3 月 2 日 - 17:09新版本特征 改进了甘特图、网络图和 PERT 图表组件的 PERT 关键路径算法。Silverlight/WPF 标准版的 DlhSoft 甘特图灯光库 DlhSoft …...

C++基础(一)—— C++概述、C++对C的扩展(作用域、struct类型、引用、内联函数、函数默认参数、函数占位参数、函数重载)

1. C概述1.1 c简介“c”中的来自于c语言中的递增运算符&#xff0c;该运算符将变量加1。c起初也叫”c withclsss”.通过名称表明&#xff0c;c是对C的扩展&#xff0c;因此c是c语言的超集&#xff0c;这意味着任何有效的c程序都是有效的c程序。c程序可以使用已有的c程序库。为什…...

Rust学习总结之if,while,loop,for使用

目录 一&#xff1a;if的使用 二&#xff1a;while的使用 三&#xff1a;loop的使用 四&#xff1a;for的使用 本文总结的四种语句&#xff08;if&#xff0c;while&#xff0c;loop&#xff0c;for&#xff09;除了loop&#xff0c;其他的三个在C语言或者Python中都是常见…...

网站做中英版/怎么做电商

2019独角兽企业重金招聘Python工程师标准>>> 参考了很多资料&#xff0c;说说自己对viewport的理解 viewport分visual viewport和layout viewport&#xff0c;visual viewport可以理解为移动设备屏幕的可视区域&#xff0c;visual viewport的大小可以理解为就是品目…...

企业网站的制作成本/国际新闻今天

大家好&#xff0c;我是 " 网游品味领导者 "X 博士。最近腾讯的回合制新游《灵山奇缘》开启内测。腾讯过往比较少涉足回合制端游这块市场&#xff0c;这次的《灵山奇缘》从推广阵势来看似乎是一款腾讯力捧的大作。那么《灵山奇缘》的素质究竟如何呢&#xff1f;和以往…...

微网站怎么自己做/销售怎么做

为了最大程度地减少USB的功耗&#xff0c;整个USB核心需要实现在DesignWare USB 2.0 nanoPHY中所采用的各种功耗节省策略。Synopsys已经在DesignWare高速USB 2.0 On-the-Go控制器&#xff08;HS OTG&#xff09;核心中实现了这些策略以及其它能够理想地适用于电池供电应用的策略…...

好的手机端网站模板下载软件/目前推广软件

1.Number.EPSILON是JS表示的最小精度 function add(a,b){if(Math.abs(a-b)<Number.EPSILON){return true;}else{return false} } console.log(add(0.10.2,0.3)) //true 2.Number.isFinite检测一个数值是否为有限数 3.Number.isNaN检测一个数值是否为NaN 4.Number.parse…...

现在做网站用什么工具/app代理推广合作50元

一.前期基础知识储备 traces.txt系统自动生成的记录anr等异常的文件&#xff0c;只记录java代码产生的异常。 如果是旧版本&#xff08;Android Studio3以下的版本&#xff09;的AS&#xff0c;可以直接通过DDMS的File Explorer直接导出来&#xff1a; 之上的AS由于移除了DD…...

wordpress主题还原/seo发包软件

标星★公众号&#xff0c;第一时间获取最新研究作者&#xff1a;Rocky Kev编译&#xff1a;公众号编辑部近期原创文章&#xff1a;♥ 基于无监督学习的期权定价异常检测(代码数据)♥ 5种机器学习算法在预测股价的应用(代码数据)♥ 深入研读&#xff1a;利用Twitter情绪去预测股…...