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

SpringBoot内嵌Tomcat连接池分析

文章目录

  • 1 Tomcat连接池
    • 1.1 简介
    • 1.2 架构图
      • 1.2.1 JDK线程池架构图
      • 1.2.2 Tomcat线程架构
    • 1.3 核心参数
      • 1.3.1 AcceptCount
      • 1.3.2 MaxConnections
      • 1.3.3 MinSpareThread/MaxThread
      • 1.3.4 MaxKeepAliveRequests
      • 1.3.5 ConnectionTimeout
      • 1.3.6 KeepAliveTimeout
    • 1.4 核心内部线程
      • 1.4.1 Acceptor
      • 1.4.2 Poller
      • 1.4.3 TomcatThreadPoolExecutor
    • 1.5 测试

1 Tomcat连接池

每个Spring Boot版本和内置容器不同,结果也不同,这里以Spring Boot 2.6.11版本 + 内置Tomcat容器举例

1.1 简介

Spring Boot 2.6.11版本中内置Tomcat版本是 9.0.65SpringBoot 内置Tomcat 的默认设置如下:

  • Tomcat 的连接等待队列长度,默认是100
  • Tomcat 的最大连接数,默认是8192
  • Tomcat 的最小工作线程数,默认是10
  • Tomcat 的最大线程数,默认是200
  • Tomcat 的连接超时时间,默认是20s

在这里插入图片描述

相关配置及默认值如下

server:tomcat:# 当所有可能的请求处理线程都在使用中时,传入连接请求的最大队列长度accept-count: 100# 服务器在任何给定时间接受和处理的最大连接数。一旦达到限制,操作系统仍然可以接受基于“acceptCount”属性的连接。max-connections: 8192threads:# 工作线程的最小数量,初始化时创建的线程数min-spare: 10# 工作线程的最大数量 io密集型建议10倍的cpu数,cpu密集型建议cpu数+1,绝大部分应用都是io密集型max: 200# 连接器在接受连接后等待显示请求 URI 行的时间。connection-timeout: 20000# 在关闭连接之前等待另一个 HTTP 请求的时间。如果未设置,则使用 connectionTimeout。设置为 -1 时不会超时。keep-alive-timeout: 20000# 在连接关闭之前可以进行流水线处理的最大HTTP请求数量。当设置为0或1时,禁用keep-alive和流水线处理。当设置为-1时,允许无限数量的流水线处理或keep-alive请求。 max-keep-alive-requests: 100

1.2 架构图

在这里插入图片描述

当连接数大于maxConnections+acceptCount + 1 时,新来的请求不会收到服务器拒绝连接响应,而是不会和新的请求进行3次握手建立连接,一段时间后(客户端的超时时间或者Tomcat的20s后)会出现请求连接超时

Tomcat扩展了线程池增强了功能:

  • JDK 线程池流程:minThreads --> queue --> maxThreads --> Exception
  • Tomcat 增强后:minThreads --> maxThreads --> queue --> Exception

点击此处了解JDK线程池

1.2.1 JDK线程池架构图

在这里插入图片描述

1.2.2 Tomcat线程架构

在这里插入图片描述

1.3 核心参数

1.3.1 AcceptCount

连接等待队列容量,等同于backlog参数,与Linux中的系统参数somaxconn取较小值,Windows中没有系统参数。

NioEndpoint.java

serverSock = ServerSocketChannel.open();
socketProperties.setProperties(serverSock.socket());
InetSocketAddress addr = new InetSocketAddress(getAddress(), getPortWithOffset());
// 这里
serverSock.socket().bind(addr,getAcceptCount());

1.3.2 MaxConnections

最大连接数
Acccptor.java

// 线程的run方法。
public void run() {    while (!stopCalled) { // 如果我们已达到最大连接数,等待connectionLimitLatch.countUpOrAwait();// 接受来自服务器套接字的下一个传入连接socket = endpoint.serverSocketAccept()// socket.close 释放的时候 调用 connectionLimitLatch.countDown();          

1.3.3 MinSpareThread/MaxThread

工作线程最小/最大线程数
AbstractEndpoint.java

// tomcat 启动时
public void createExecutor() {internalExecutor = true;// 容量为Integer.MAX_VALUETaskQueue taskqueue = new TaskQueue();TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-", daemon, getThreadPriority());// Tomcat扩展的线程池executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);taskqueue.setParent( (ThreadPoolExecutor) executor);
}

1.3.4 MaxKeepAliveRequests

长连接,在发送了maxKeepAliveRequests个请求后就会被服务器端主动断开连接。

在连接关闭之前可以进行流水线处理的最大HTTP请求数量。当设置为0或1时,禁用keep-alive和流水线处理。当设置为 -1 时,允许无限数量的流水线处理或 keep-alive 请求。

较大的 MaxKeepAliveRequests 值可能会导致服务器上的连接资源被长时间占用。根据具体需求,可以根据服务器的负载资源配置来调整 MaxKeepAliveRequests 的值,以平衡并发连接和服务器资源的利用率。

NioEndpoint.setSocketOptions socketWrapper.setKeepAliveLeft(NioEndpoint.this.getMaxKeepAliveRequests());Http11Processor.service(SocketWrapperBase<?> socketWrapper)keepAlive = true;while(!getErrorState().isError() && keepAlive && !isAsync() && upgradeToken == null &&sendfileState == SendfileState.DONE && !protocol.isPaused()) {// 默认100  int maxKeepAliveRequests = protocol.getMaxKeepAliveRequests();if (maxKeepAliveRequests == 1) {keepAlive = false;} else if (maxKeepAliveRequests > 0 &&//    socketWrapper.decrementKeepAlive() <= 0) {keepAlive = false;}

1.3.5 ConnectionTimeout

连接的生存周期,当已经建立的连接,在 connectionTimeout 时间内,如果没有请求到来,服务端程序将会主动关闭该连接。

Tomcat 9中,ConnectionTimeout的默认值是20000毫秒,也就是20秒

如果该时间过长,服务器将要等待很长时间才会收到客户端的请求结果,从而导致服务效率低下。如果该时间过短,则可能会出现客户端在请求过程中网络慢等问题,而被服务器取消连接的情况。
由于某个交换机或者路由器出现了问题,导致某些post大文件的请求堆积在交换机或者路由器上,tomcat的工作线程一直拿不到完整的文件数据。

NioEndpoint.Poller#run()// Check for read timeoutif ((socketWrapper.interestOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {long delta = now - socketWrapper.getLastRead();long timeout = socketWrapper.getReadTimeout();if (timeout > 0 && delta > timeout) {readTimeout = true;}}// Check for write timeoutif (!readTimeout && (socketWrapper.interestOps() & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE) {long delta = now - socketWrapper.getLastWrite();long timeout = socketWrapper.getWriteTimeout();if (timeout > 0 && delta > timeout) {writeTimeout = true;}}

1.3.6 KeepAliveTimeout

等待另一个 HTTP 请求的时间,然后关闭连接。当未设置时,将使用 connectionTimeout。当设置为 -1 时,将没有超时。

Http11InputBuffer.parseRequestLine// Read new bytes if needed
if (byteBuffer.position() >= byteBuffer.limit()) {if (keptAlive) {// 还没有读取任何请求数据,所以使用保持活动超时wrapper.setReadTimeout(keepAliveTimeout);}if (!fill(false)) {// A read is pending, so no longer in initial stateparsingRequestLinePhase = 1;return false;}//  至少已收到请求的一个字节 切换到套接字超时。wrapper.setReadTimeout(connectionTimeout);
}

1.4 核心内部线程

1.4.1 Acceptor

Acceptor:接收器,作用是接受scoket网络请求,并调用setSocketOptions()封装成为NioSocketWrapper,并注册到Pollerevents中。注意查看run方法org.apache.tomcat.util.net.Acceptor#run

public void run() {while (!stopCalled) {// 等待下一个请求进来socket = endpoint.serverSocketAccept();// 注册socket到Poller,生成PollerEvent事件endpoint.setSocketOptions(socket);// 向轮询器注册新创建的套接字- poller.register(socketWrapper);- (SynchronizedQueue(128))events.add(new PollerEvent(socketWrapper))  

1.4.2 Poller

Poller:轮询器,轮询是否有事件达到,有请求事件到达后,以NIO的处理方式,查询Selector取出所有请求,遍历每个请求的需求,分配给Executor线程池执行。查看org.apache.tomcat.util.net.NioEndpoint.Poller#run()

public void run() {while (true) {//查询selector取出所有请求事件Iterator<SelectionKey> iterator =keyCount > 0 ? selector.selectedKeys().iterator() : null;// 遍历就绪键的集合并调度任何活动事件。while (iterator != null && iterator.hasNext()) {SelectionKey sk = iterator.next();iterator.remove();NioSocketWrapper socketWrapper = (NioSocketWrapper) sk.attachment();// 分配给Executor线程池执行处理请求keyif (socketWrapper != null) {processKey(sk, socketWrapper);- processSocket(socketWrapper, SocketEvent.OPEN_READ/SocketEvent.OPEN_WRITE)- executor.execute((Runnable)new SocketProcessor(socketWrapper,SocketEvent))}}

1.4.3 TomcatThreadPoolExecutor

真正执行连接读写操作的线程池,在JDK线程池的基础上进行了扩展优化。

AbstractEndpoint.java

public void createExecutor() {internalExecutor = true;TaskQueue taskqueue = new TaskQueue();TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-", daemon, getThreadPriority());// tomcat自定义线程池executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);taskqueue.setParent( (ThreadPoolExecutor) executor);}

TomcatThreadPoolExecutor.java

// 与 java.util.concurrent.ThreadPoolExecutor 相同,但实现了更高效的getSubmittedCount()方法,用于正确处理工作队列。
// 如果未指定 RejectedExecutionHandler,将配置一个默认的,并且该处理程序将始终抛出 RejectedExecutionException
public class ThreadPoolExecutor extends java.util.concurrent.ThreadPoolExecutor {// 已提交但尚未完成的任务数。这包括队列中的任务和已交给工作线程但后者尚未开始执行任务的任务。// 这个数字总是大于或等于getActiveCount() 。private final AtomicInteger submittedCount = new AtomicInteger(0);@Overrideprotected void afterExecute(Runnable r, Throwable t) {if (!(t instanceof StopPooledThreadException)) {submittedCount.decrementAndGet();}@Overridepublic void execute(Runnable command){// 提交任务的数量+1submittedCount.incrementAndGet();try {//  线程池内部方法,真正执行的方法。就是JDK线程池原生的方法。super.execute(command);} catch (RejectedExecutionException rx) {// 再次把被拒绝的任务放入到队列中。if (super.getQueue() instanceof TaskQueue) {final TaskQueue queue = (TaskQueue)super.getQueue();try {//强制的将任务放入到阻塞队列中if (!queue.force(command, timeout, unit)) {//放入失败,则继续抛出异常submittedCount.decrementAndGet();throw new RejectedExecutionException(sm.getString("threadPoolExecutor.queueFull"));}} catch (InterruptedException x) {//被中断也抛出异常submittedCount.decrementAndGet();throw new RejectedExecutionException(x);}} else {//不是这种队列,那么当任务满了之后,直接抛出去。submittedCount.decrementAndGet();throw rx;}}}
/*** 实现Tomcat特有逻辑的自定义队列*/
public class TaskQueue extends LinkedBlockingQueue<Runnable> {private static final long serialVersionUID = 1L;private transient volatile ThreadPoolExecutor parent = null;private static final int DEFAULT_FORCED_REMAINING_CAPACITY = -1;/*** 强制遗留的容量*/private int forcedRemainingCapacity = -1;/*** 队列的构建方法*/public TaskQueue() {}public TaskQueue(int capacity) {super(capacity);}public TaskQueue(Collection<? extends Runnable> c) {super(c);}/*** 设置核心变量*/public void setParent(ThreadPoolExecutor parent) {this.parent = parent;}/*** put:向阻塞队列填充元素,当阻塞队列满了之后,put时会被阻塞。* offer:向阻塞队列填充元素,当阻塞队列满了之后,offer会返回false。** @param o 当任务被拒绝后,继续强制的放入到线程池中* @return 向阻塞队列塞任务,当阻塞队列满了之后,offer会返回false。*/public boolean force(Runnable o) {if (parent == null || parent.isShutdown()) {throw new RejectedExecutionException("taskQueue.notRunning");}return super.offer(o);}/*** 带有阻塞时间的塞任务*/@Deprecatedpublic boolean force(Runnable o, long timeout, TimeUnit unit) throws InterruptedException {if (parent == null || parent.isShutdown()) {throw new RejectedExecutionException("taskQueue.notRunning");}return super.offer(o, timeout, unit); //forces the item onto the queue, to be used if the task is rejected}/*** 当线程真正不够用时,优先是开启线程(直至最大线程),其次才是向队列填充任务。** @param runnable 任务* @return false 表示向队列中添加任务失败,*/@Overridepublic boolean offer(Runnable runnable) {if (parent == null) {return super.offer(runnable);}//若是达到最大线程数,进队列。if (parent.getPoolSize() == parent.getMaximumPoolSize()) {return super.offer(runnable);}//当前活跃线程为10个,但是只有8个任务在执行,于是,直接进队列。if (parent.getSubmittedCount() < (parent.getPoolSize())) {return super.offer(runnable);}//当前线程数小于最大线程数,那么直接返回false,去创建最大线程if (parent.getPoolSize() < parent.getMaximumPoolSize()) {return false;}//否则的话,将任务放入到队列中return super.offer(runnable);}/*** 获取任务*/@Overridepublic Runnable poll(long timeout, TimeUnit unit) throws InterruptedException {Runnable runnable = super.poll(timeout, unit);//取任务超时,会停止当前线程,来避免内存泄露if (runnable == null && parent != null) {parent.stopCurrentThreadIfNeeded();}return runnable;}/*** 阻塞式的获取任务,可能返回null。*/@Overridepublic Runnable take() throws InterruptedException {//当前线程应当被终止的情况下:if (parent != null && parent.currentThreadShouldBeStopped()) {long keepAliveTime = parent.getKeepAliveTime(TimeUnit.MILLISECONDS);return poll(keepAliveTime, TimeUnit.MILLISECONDS);}return super.take();}/*** 返回队列的剩余容量*/@Overridepublic int remainingCapacity() {if (forcedRemainingCapacity > DEFAULT_FORCED_REMAINING_CAPACITY) {return forcedRemainingCapacity;}return super.remainingCapacity();}/*** 强制设置剩余容量*/public void setForcedRemainingCapacity(int forcedRemainingCapacity) {this.forcedRemainingCapacity = forcedRemainingCapacity;}/*** 重置剩余容量*/void resetForcedRemainingCapacity() {this.forcedRemainingCapacity = DEFAULT_FORCED_REMAINING_CAPACITY;}
} 

1.5 测试

如下配置举例

server:port: 8080tomcat:accept-count: 3max-connections: 6threads:min-spare: 2max: 3

使用ss -nlt查看全连接队列容量。

ss -nltp
ss -nlt|grep 8080
- Recv-Q 表示客户端有多少个字节发送但还没有被服务端接收
- Send-Q 表示有多少个字节未被客户端接收

静默状态
在这里插入图片描述

相关文章:

SpringBoot内嵌Tomcat连接池分析

文章目录 1 Tomcat连接池1.1 简介1.2 架构图1.2.1 JDK线程池架构图1.2.2 Tomcat线程架构 1.3 核心参数1.3.1 AcceptCount1.3.2 MaxConnections1.3.3 MinSpareThread/MaxThread1.3.4 MaxKeepAliveRequests1.3.5 ConnectionTimeout1.3.6 KeepAliveTimeout 1.4 核心内部线程1.4.1 …...

分布式协调服务中的几个常见算法

分布式协调服务中的几个常见算法包括: 1. 选主算法 用于从多个节点中选举出一个节点作为主节点或者领导者,常见的算法有Bully算法、Ring算法等。 2. 原子广播算法 用于向分布式系统中的所有节点广播消息,保证所有节点都可以收到消息,典型的两阶段提交协议实现了原子广播。…...

易服客工作室:Houzez主题 - 超级房地产WordPress主题/网站

Houzez主题是全球流行的房地产经纪人和公司的WordPress主题。 Houzez Theme是专业设计师创造一流设计的超级灵活起点。它具有您的客户&#xff08;房地产经纪人或公司&#xff09;甚至可能做梦也想不到的功能。 网址&#xff1a;Houzez主题 - 超级房地产WordPress主题/网站 - …...

mysql通过binlog日志恢复误删数据

1、先查看binlog功能是否开启 show variables like %log_bin%;log_bin为ON说明可以使用binlog恢复&#xff0c;如果为OFF说明没有开启binlog。 2、删除部分数据做测试 3、查找binlog文件位置 show variables like %datadir%;cd /var/lib/mysqlls -l删除数据时间是在文件154与…...

Istio入门体验系列——基于Istio的灰度发布实践

导言&#xff1a;灰度发布是指在项目迭代的过程中用平滑过渡的方式进行发布。灰度发布可以保证整体系统的稳定性&#xff0c;在初始发布的时候就可以发现、调整问题&#xff0c;以保证其影响度。作为Istio体验系列的第一站&#xff0c;本文基于Istio的流量治理机制&#xff0c;…...

CSS行内,内部,外部以及优先级

1.内联样式表&#xff1a; 将样式编写到style标签里 <style>.context {color: red;} </style> 2. 行内样式&#xff1a; 在 HTML 标签中使用 style 属性设置 CSS 样式 <div style"font-size: 18px;">行内样式</div> 3.外联样式&#xff1…...

LCA——最近公共祖先

LCA问题是指在一棵树中找到两个节点的最近公共祖先。最近公共祖先是指两个节点在树中的最近的共同祖先节点。例如&#xff0c;在下面这棵树中&#xff0c;节点 6 6 6和节点7的最近公共祖先是节点 3 3 3。 1/ \2 3/ \ / \4 5 6 7解决LCA问题的方法有很多种&#xff…...

游戏开发与硬件结合,开启全新游戏体验!

游戏与硬件的结合可以通过多种方式实现&#xff0c;从改善游戏体验到创造全新的游戏玩法。以下是一些常见的游戏与硬件结合的方式&#xff1a; 虚拟现实&#xff08;VR&#xff09;和增强现实&#xff08;AR&#xff09;技术&#xff1a;VR和AR技术使玩家能够沉浸式地体验游戏…...

测试框架pytest教程(4)运行测试

运行测试文件 $ pytest -q test_example.py 会运行该文件内test_开头的测试方法 该-q/--quiet标志使输出保持简短 测试类 pytest的测试用例可以不写在类中&#xff0c;但如果写在类中&#xff0c;类名需要是Test开头&#xff0c;非Test开头的类下的test_方法不会被搜集为用…...

Linux 上 离线部署GeoScene Server Py3 运行时环境

默认安装ArcGIS Pro的时候&#xff0c;会自动部署上Python3环境&#xff0c;所以在windows上不需要考虑这个问题&#xff0c;但是linux默认并不部署Py3&#xff0c;因此需要单独部署&#xff0c;具体部署可以参考Linux 上 ArcGIS Server 的 Python 3 运行时—ArcGIS Server | A…...

Python+request+unittest实现接口测试框架集成实例

这篇文章主要介绍了Pythonrequestunittest实现接口测试框架集成实例&#xff0c;小编觉得挺不错的&#xff0c;现在分享给大家&#xff0c;也给大家做个参考。一起跟随小编过来看看吧 1、为什么要写代码实现接口自动化 大家知道很多接口测试工具可以实现对接口的测试&#xf…...

django/flask+python+vue汽车租赁管理系统_1ma2x

开发语言&#xff1a;Python 框架&#xff1a;django/flask Python版本&#xff1a;python3.7.7 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat 开发软件&#xff1a;PyCharm . 课题主要分为三大模块&#xff1a;即管理员模块、用户模块和普通管理员模块&#xff0…...

胜者打仗,就像高山上决开积水,势不可挡

胜者打仗&#xff0c;就像高山上决开积水&#xff0c;势不可挡 【安志强趣讲《孙子兵法》16讲】 【原文】 是故胜兵先胜而后求战&#xff0c;败兵先战而后求胜。善用兵者&#xff0c;修道而保法&#xff0c;故能为胜败之政。 【注释】 修道&#xff1a;指从各方面修治“先立于不…...

stm32的命令规则

stm32型号的说明&#xff1a;以STM32F103RBT6这个型号的芯片为例&#xff0c;该型号的组成为7个部分&#xff0c;其命名规则如下&#xff1a;...

1. HBase中文学习手册之揭开Hbase的神秘面纱

揭开Hbase的神秘面纱 1.1 欢迎使用 Apache Hbase1.1.1 什么是 Hbase?1.1.2 Hbase的前世今生1.1.3 HBase的技术选型&#xff1f;1.1.3.1 不适合使用 HBase的场景1.1.3.2 适合使用 HBase的场景 1.1.4 HBase的特点1.1.4.1 HBase的优点1.1.4.2 HBase的缺点 1.1.5 HBase设计架构 1.…...

[线程/C++]线程同(异)步和原子变量

文章目录 1.线程的使用1.1 函数构造1.2 公共成员函数1.2.1 get_id()1.2.2 join()2.2.3 detach()2.2.5 joinable()2.2.6 operator 1.3 静态函数1.4 call_once 2. this_thread 命名空间2.1 get_id()2.2 sleep_for()2.3 sleep_until()2.4 yield() 3. 线程同步之互斥锁3.1 std:mute…...

全球网络加速器GA和内容分发网络CDN,哪个更适合您的组织使用?

对互联网用户来说&#xff0c;提供最佳的用户体验至关重要&#xff1a;网页加载时间过长、视频播放断断续续以及服务忽然中断等问题都足以在瞬间失去客户。因此可以帮助提高您的网站或APP提高加载性能的解决方案就至关重要&#xff1a;全球网络加速器和CDN就是其中的两种解决方…...

蓝凌OA custom.jsp 任意文件读取

​曾子曰&#xff1a;“慎终追远&#xff0c;民德归厚矣。” 漏洞复现 访问漏洞url&#xff1a; 出现漏洞的文件为 custom.jsp&#xff0c;构造payload&#xff1a; /sys/ui/extend/varkind/custom.jsp var{"body":{"file":"file:///etc/passwd&q…...

(二)结构型模式:7、享元模式(Flyweight Pattern)(C++实例)

目录 1、享元模式&#xff08;Flyweight Pattern&#xff09;含义 2、享元模式的UML图学习 3、享元模式的应用场景 4、享元模式的优缺点 5、C实现享元模式的简单实例 1、享元模式&#xff08;Flyweight Pattern&#xff09;含义 享元模式&#xff08;Flyweight&#xff09…...

laravel 多次查询请求,下次请求清除上次请求的where 条件

在Laravel中&#xff0c;可以使用where方法来添加查询条件&#xff0c;但是每次添加where条件时&#xff0c;都会在查询构造器中持久化这些条件&#xff0c;直到你手动重置它们。所以&#xff0c;如果你想在下一次查询中清除上次查询的where条件&#xff0c;有以下几种选择&…...

C++根据如下使用类MyDate的程序,写出类MyDate的定义,MyDate中有三个数据成员:年year,月month,日day完成以下要求

题目&#xff1a; 根据如下使用类MyDate的程序&#xff0c;写出类MyDate的定义&#xff0c;MyDate中有三个数据成员&#xff1a; 年year&#xff0c;月month&#xff0c;日day int year,month,day; void main() { MyDate d1, d2; d1.set(2015, 12, 31); d2.set(d1); d1.…...

微盟集团中报增长稳健 重点发力智慧零售AI赛道

零售数字化进程已从渠道构建走向了用户的深度运营。粗放式用户运营体系无法适应“基于用户增长所需配套的精细化运营能力”,所以需要有个体、群体、个性化、自动化运营——即在对的时候、以对的方式、把对的内容推给用户。 出品|产业家 2023年已经过半&#xff0c;经济复苏成为…...

设计模式(7)模板方法模式

一、定义&#xff1a; 定义一个操作中的算法骨架&#xff0c;而将算法的一些步骤延迟到子类中&#xff0c;使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。它是一种类行为型模式。 //模板方法抽象类 public abstract class AbstractClass {//模板方法publ…...

2308C++协程流程9

参考 #include <协程> #include "简异中.cpp" //用来中文定义的.元<类 T>构 P;元<类 T>构 任务{用 承诺型P<T>;任务()默认;动 符号 协待()常 无异{构 等待器{极 直接协()常 无异{中 p.是准备好();}协柄 挂起协(协柄<>o)常 无异{p.连续…...

基于学习交流社区的自动化测试实现

一 项目介绍 项目名称 项目名称&#xff1a; 学习交流社区 项目介绍 项目介绍&#xff1a; 学习交流社区是一个基于Spring的前后端分离的在线论坛系统。使用了MySQL数据库来存储相关信息&#xff0c;项目完成后使用Xshell将其部署到云服务器上。 前端页面&#xff1a; 前端共由…...

2023-08-21力扣每日一题

链接&#xff1a; 2337. 移动片段得到字符串 题意&#xff1a; L可以和左边的_交换&#xff0c;R可以和右边的_交换&#xff0c;求判断A是否能通过交换&#xff08;不限次数&#xff09;变成B 解&#xff1a; 观察可知&#xff0c;如果存在RL,一定不能交换出LR&#xff0c…...

对象存储服务-MinIO基本集成

是什么 MinIO 是一个高性能的分布式对象存储服务&#xff0c;适合存储非结构化数据&#xff0c;如图片&#xff0c;音频&#xff0c;视频&#xff0c;日志等。对象文件最大可以达到5TB。 安装启动 mkdir -p /usr/local/minio cd /usr/local/minio# 下载安装包 wget https:/…...

Yarn介绍及快速安装 - Debian/Ubuntu Linux

1.Yarn介绍 Yarn 是一个用于管理 JavaScript 包的快速、可靠和安全的包管理器。它是由 Facebook、Google、Exponent 和 Tilde 团队共同开发的&#xff0c;旨在提供比 npm 更快速、可靠的包管理体验。 以下是 Yarn 的一些主要特点和优势&#xff1a; 快速安装&#xff1a;Yarn…...

【新日语(2)】第10課 中国の生活に慣れるかどうか少し心配です

第10課 中国の生活に慣れるかどうか少し心配です 注释&#xff1a; &#xff5e;かどうか&#xff1a;“是否”。 练习A 一、例句 田中さんは鈴木さんに、30分ぐらい遅れると言いました。 田中先生告诉铃木先生&#xff0c;他会迟到大约30分钟。 注释&#xff1a; &…...

Python 网页解析初级篇:BeautifulSoup库的入门使用

在Python的网络爬虫中&#xff0c;网页解析是一项重要的技术。而在众多的网页解析库中&#xff0c;BeautifulSoup库凭借其简单易用而广受欢迎。在本篇文章中&#xff0c;我们将学习BeautifulSoup库的基本用法。 一、BeautifulSoup的安装与基本使用 首先&#xff0c;我们需要使…...

ppt成品网站/山东疫情最新情况

interface{} interface{} 接口、interface{} 类型很多人都会混淆。interface{} 类型是没有方法的接口。由于没有 implements 关键字&#xff0c;所以说所有的类型都至少实现了 0 个方法&#xff0c;所有类型都实现了空接口。这意味着&#xff0c;如果编写一个函数以 interface{…...

三五互联网站管理登录地址是多少/东莞有限公司seo

配置druid时&#xff0c;要把druid.propertites文件放到resources文件夹中 不然就会报“instream parameter is null”...

广州专业网站制作公司/销售平台排名

例如&#xff0c;用户名test1改为test2&#xff0c;在plsql界面中不支持直接更改用户名&#xff0c;只能通过sql更改1、查询系统user$中的user#值select user#,name from user$ where name test1;2、根据user#值&#xff0c;更改用户名update user$ set nametest2 where user…...

校园网站集群建设/信息推广平台

重要声明:本文出自公众号:《管理的常识》"知乎7万赞回答&#xff1a;你思考问题的方式&#xff0c;决定了你的层次"一文。本人觉得写得蛮好&#xff0c;分享给大家&#xff0c;共勉&#xff01;文章有点长&#xff0c;看完全文需要点耐心…… 所谓厉害的人&#xff0…...

前端做网站一般用什么框架/中视频自媒体账号注册下载

在自己学习java语言的过程中&#xff0c;很容易把break和continue的用法混淆。为了便于以后快速查阅及温习&#xff0c;在此特留学习笔记一份。简述在任何迭代语句的主体部分&#xff0c;都可以用break和continue控制循环的流程。其中&#xff0c;break用于强行退出循环&#x…...

网站建设服务商/如何给公司网站做推广

1. 引理1 2. 引理2 3. 定理1 4. 逆矩阵求解示例1 5. 逆矩阵求解示例2&#xff08;伴随矩阵的逆矩阵的求解&#xff09;...