转:https://blog.csdn.net/lz710117239/article/details/77414726
Reactor单线程模型
1.作为NIO服务端,接收客户端的TCP连接 2.作为NIO客户端,向服务端发起TCP连接 3.读取通信对端的请求或者应答消 4.向通信对端发送消息请求或者应答消息
Reactor单线程模型如下图所示:
由于Reactor模式使用的是异步非阻塞I/O,所有的I/O操作都不会导致阻塞,理论上一个线程可以独立处理所有I/O相关的操作。从架构层面上看,一个NIO线程确实可以完成其承担的职责。例如,通过Acceptor类接收客户端的TCP连接请求信息,当链路建立成功之后,通过Dispatch将对应的ByteBuffer派发到指定的Handler上,进行消息解码。用户线程消息编码后通过NIO线程将消息发送给客户端。
在一些小容量的应用场景下,可以使用单线程模型。但是这对于高负载,大并发的应用场景却不合适,主要原因如下。
1.一个NIO线程同时处理成百上千的链路,性能上无法支撑,即便NIO线程的CPU负荷达到100%,也无法满足海量消息的编码,解码,读取和发送。 2.当NIO线程负载过重之后,处理速度将变慢,这会导致大量客户端连接超时,超时之后往往会进行重发,这更加NIO线程的负载,最终会导致大量消息挤压和处理超时,成为系统的性能瓶颈。 3.可靠性问题:一旦NIO线程意外跑飞,或者进入死循环,会导致整个系统通信模块不可用,不能接收和处理外部消息,造成节点故障。
Reactor多线程模型
Reactor多线程模型与单线程模型最大的却别就是有一组NIO线程来处理I/O操作,它的原理如图所示:
Reactor多线程模型的特点如下所示: 1.有专门一个NIO线程——Acceptor线程用于监听服务端,接收客户端的TCP连接请求。 2.网络I/O操作——读,写等由一个NIO线程负责,线程池可以采用标准的JDK线程池实现,它包含一个任务队列和N个可用的线程,由这些NIO线程负责消息的读取,解码,编码和发送。 3.一个NIO线程可以同时处理N条链路,但是一个链路只对应一个NIO线程,防止发生并发操作问题。
在大多数场景下,Reactor多线程模型可以满足性能需求。但是,在个别特殊场景中,一个NIO线程负责监听和处理所有的客户端链接可能会存在性能问题。例如并发百万客户端连接,或者服务端需要对客户端握手进行安全认证,但是认证本身非常损耗性能。在这类场景下,单独一个Acceptor线程可能会存在性能不足的问题,为了解决性能问题,产生了第三种Reactor线程模型——主从Reactor多线程模型。
主从Reactor多线程模型
主从Reactor线程模型的特点是:服务端用于接收客户端链接的不在是一个单独的NIO线程,而是一个独立的NIO线程池。Acceptor接收到客户端TCP链接请求并处理完成后(可能包含接入认证等),将新创建的SocketChannel注册到I/O线程池(sub reacotr线程池)的某个I/O线程上,由它负责SocketChannel的读写和编码工作。Acceptor线程池仅仅用于客户端登录,握手,和安全认证,一旦链路建立成功,就将链路注册到后端subReactor线程池的I/O线程上,有I/O线程负责后续的I/O操作。
利用主从NIO线程模型,可以解决一个服务端监听线程无法有效处理所有客户端连接的性能不足问题。因此,在Netty的官方Demo中,推荐使用该线程模型。
Netty的线程模型
Netty的线程模型并不是一成不变的,它实际取决于用户的启动参数配置。通过设置不同的启动参数,Netty可以同时支持Reactor单线程模型,多线程模型和主从Reactor多线程模型。如下图:
通过服务端启动代码来了解它的线程模型:
//配置服务端的NIO线程组
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try{
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 1024)
.childHandler(new ChildChannelHandler());
//绑定端口,同步等待成功
ChannelFuture f = b.bind(port).sync();
//等待服务端监听端口关闭
f.channel().closeFuture().sync();
}finally {
//优雅退出,释放线程池资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
服务端启动的时候,创建了两个NioEventLoopGroup,它们实际是两个独立的Reactor线程池。一个用于接收客户端的TCP连接,另一个用于处理I/O相关的读写操作,或者执行系统Task,定时任务Task等。 Netty用于接收客户端请求的线程池职责如下。 (1)接收客户端TCP连接欸,初始化Channel参数; (2)将链路状态变更事件通知给ChannelPipeline。 Netty处理I/O操作的Reactor线程池职责如下。 (1)异步读取通信对端的数据报,发送读事件到ChannelPipeline; (2)异步发送消息到通信对端,调用ChannelPipeline的消息发送接口; (3)执行系统调用Task; (4)执行定时任务Task,例如链路空闲状态检测定时任务。 通过调整线程池的线程个数,是否共享线程池等方式,Netty的Reactor线程模型可以在单线程,多线程和主从多线程间切换,这种灵活的配置方式可以最大程度地满足不同用户的个性化定制。
为了尽可能地提升性能,Netty在很多地方进行了无锁化的设计,例如在I/O线程内部进行穿行操作,避免多线程竞争导致的性能下降问题。表面上看,串行化似乎CPU利用率不高,并发程度不够。但是,通过调整NIO线程池的线程参数,可以同hi启动多个串行化的线程并行运行,这种局部无锁化的串行线程设计相比一个队列——多个工作线程的模型性能更好。
它的设计原理如下如所示:
Netty的NioEventLoop读取到消息之后,直接调用ChannelPipeline的fireChannelRead(Object msg)。只要用户不主动切换线程,一直都是由NioEventLoop调用用户的handler,期间不进行线程切换。这种串行化处理方式避免了多线程操作导致的锁的竞争,从性能角度看是最优的。
NioEventLoop源码分析
NioEventLoop设计原理
Netty的NioEventLoop并不是要给纯粹的I/O线程,它除了负责I/O的读写之外,还兼顾处理以下两类任务。
系统Task:通过调用NioeventLoop的execute(Runnable task)方法实现,Netty有很多系统Task,创建它们的主要原因是:当I/O线程和用户线程同时操作网络资源时,为了防止并发操作导致的锁竞争,将用户线程的操作封装成Task放入消息队列中,由I/O线程负责执行,这样就实现了局部无锁化。 定时任务:调用NioEventLoop的schedule(Runnable command,long delay,TimeUnit unit)方法实现。 正是因为NioEventLoop具备多种职责,所以它的实现比较特殊,它并不是简单的Runnable,我们来看下它们的继承关系。如下:
它实现了EventLoop接口、EventExecutorGroup接口和ScheduledExecutorService接口,正是因为这种设计,导致NioEventLoop和其父类功能实现非常复杂。下面我们重点分析下它的源码实现:
NioEventLoop
作为NIO框架的Reactor线程,NioEventLoop需要处理网络I/O读写事件,因此它必须聚合一个多路复用器对象,看下它的selector定义:
Selector selector;
private SelectedSelectionKeySet selectedKeys;
private final SelectorProvider provider;
直接调用Selector.open()就能创建并打开一个新的Selector。 然后通过反射对selectedKeys进行优化:
try {
SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();
Class selectorImplClass =
Class.forName("sun.nio.ch.SelectorImpl", false, ClassLoader.getSystemClassLoader());
// Ensure the current selector implementation is what we can instrument.
if (!selectorImplClass.isAssignableFrom(selector.getClass())) {
return selector;
}
Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");
Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");
selectedKeysField.setAccessible(true);
publicSelectedKeysField.setAccessible(true);
selectedKeysField.set(selector, selectedKeySet);
publicSelectedKeysField.set(selector, selectedKeySet);
selectedKeys = selectedKeySet;
logger.trace("Instrumented an optimized java.util.Set into: {}", selector);
上面代码,如果开启了selectedKeys优化功能,通过反射的方法从Selector实例中获取selectedKeys和publicSelectedKeys将上述两个成员变量设置为可写,通过反射的方式使用Netty构造的selectedKeys包装类selectedKeySet将原JDK的selectedKeys替换掉。默认为开启优化功能。 下面看下run()方法的实现:
for (;;) {
oldWakenUp = wakenUp.getAndSet(false);
try {
if (hasTasks()) {
selectNow();
} else {
select();
Selector的selectNow()方法会立即触发Selector的选择操作,如果有准备就绪的Channel,则返回就绪的Channel集合。选择完成后在此判断用户是否调用了Selector的wakeup方法,如果调用,执行selector.wakeup()操作。下面我们返回到run()方法,继续分析代码。如果消息队列中没有消息需要处理,则执行select()方法,有Selector多路复用器轮询,看是否有准备就绪的channel。它的实现如下: 取当前系统的纳秒时间,调用delayNanos()方法计算获得NioEventLoop中定时任务的触发时间。
private void select() throws IOException {
Selector selector = this.selector;
try {
int selectCnt = 0;
long currentTimeNanos = System.nanoTime();
long selectDeadLineNanos = currentTimeNanos + delayNanos(currentTimeNanos);
for (;;) {
long timeoutMillis = (selectDeadLineNanos - currentTimeNanos + 500000L) / 1000000L;
if (timeoutMillis <= 0) {
if (selectCnt == 0) {
selector.selectNow();
selectCnt = 1;
}
break;
}
int selectedKeys = selector.select(timeoutMillis);
selectCnt ++;
if (selectedKeys != 0 || oldWakenUp || wakenUp.get() || hasTasks()) {
// Selected something,
// waken up by user, or
// the task queue has a pending task.
break;
}
if (SELECTOR_AUTO_REBUILD_THRESHOLD > 0 &&
selectCnt >= SELECTOR_AUTO_REBUILD_THRESHOLD) {
// The selector returned prematurely many times in a row.
// Rebuild the selector to work around the problem.
logger.warn(
"Selector.select() returned prematurely {} times in a row; rebuilding selector.",
selectCnt);
rebuildSelector();
selector = this.selector;
// Select again to populate selectedKeys.
selector.selectNow();
selectCnt = 1;
break;
}
计算下一个将要触发的定时任务的剩余超时时间,将它转换为毫秒,为超时时间增加0.5毫秒的调整值。对剩余的超时时间进行判断,如果需要立即执行或者已经超时,则调用selector.selectNow()进行轮询操作,将selectCnt设置为1,并退出当前循环。 将定时任务剩余的超时时间作为参数进行select操作,没完成一次select操作,对select计数器selectCnt加1. Select操作完成之后,需要对结果进行判断,如果存在下列任意一种情况,则退出当前循环。 1.有Channel处于就绪状态,selectedKeys不为0,说明有读写事件需要处理。 2.oldWakenUp为true; 3.系统或者用户调用了wakeup操作,唤醒当前的多路复用器; 4.消息队列中有新的任务需要处理。 如果本次Selector的轮询结果为空,也没有wakeup操作或者是新的消息需要处理,则说明是个空轮询,有可能触发了JDK的epoll bug,它会导致Selector的空轮询,使I/O线程一致处于100%状态。这个问题一直到JDK1.8才得到解决。 解决方式就是上面代码最下面的那层if语句。 (1)对Selector的select周期进行统计; (2)每完成一次select操作进行一次计数; (3)当select的操作达到一定次数后,rebuildSelector()重新轮询。
newSelector = openSelector();
} catch (Exception e) {
logger.warn("Failed to create a new Selector.", e);
return;
}
// Register all channels to the new Selector.
int nChannels = 0;
for (;;) {
try {
for (SelectionKey key: oldSelector.keys()) {
Object a = key.attachment();
try {
if (key.channel().keyFor(newSelector) != null) {
continue;
}
int interestOps = key.interestOps();
key.cancel();
key.channel().register(newSelector, interestOps, a);
nChannels ++;
} catch (Exception e) {
logger.warn("Failed to re-register a Channel to the new Selector.", e);
if (a instanceof AbstractNioChannel) {
AbstractNioChannel ch = (AbstractNioChannel) a;
ch.unsafe().close(ch.unsafe().voidPromise());
} else {
@SuppressWarnings("unchecked")
NioTask task = (NioTask) a;
invokeChannelUnregistered(task, key, e);
}
}
}
} catch (ConcurrentModificationException e) {
// Probably due to concurrent modification of the key set.
continue;
}
break;
}
selector = newSelector;
通过销毁旧的、有问题的多路复用器,使用新建的Selector就可以解决空轮询Selector导致的I/O线程CPU占用100%的问题。 如果轮询到了处于就绪状态的SocketChannel,则需要处理网络I/O事件,相关代码如下:
if (selectedKeys != null) {
processSelectedKeysOptimized(selectedKeys.flip());
} else {
processSelectedKeysPlain(selector.selectedKeys());
}
由于默认开启了selectedKeys的优化功能,所以会进入processSelectedKeysOptimized分支执行。进入该方法,如果有需要处理的channel则进入processSelectedKey方法中,处理I/O事件,其代码如下:
final NioUnsafe unsafe = ch.unsafe();
if (!k.isValid()) {
// close the channel if the key is not valid anymore
unsafe.close(unsafe.voidPromise());
return;
}
首先从NioServerSocketChannel或者NioSocketChannel中获取其内部类Unsafe,判断当前选择键是否可用,如果不可用,调用Unsafe的close()方法,释放连接资源。 如果选择键可用,则继续对网络操作位进行判断,代码如下:
int readyOps = k.readyOps();
// Also check for readOps of 0 to workaround possible JDK bug which may otherwise lead
// to a spin loop
if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
unsafe.read();
if (!ch.isOpen()) {
// Connection already closed - no need to handle write.
return;
}
}
如果是读或者连接操作,则调用Unsafe的read方法。此处Unsafe的实现是个多态,对于NioServerSocketChannel,它的读操作就是接收客户端的TCP连接,相关代码如下:
protected int doReadMessages(List buf) throws Exception {
SocketChannel ch = javaChannel().accept();
try {
if (ch != null) {
buf.add(new NioSocketChannel(this, childEventLoopGroup().next(), ch));
return 1;
}
} catch (Throwable t) {
logger.warn("Failed to create a new channel from an accepted socket.", t);
try {
ch.close();
} catch (Throwable t2) {
logger.warn("Failed to close a socket.", t2);
}
}
return 0;
}
对于NioSocketChannel,它的读操作就是从SocketChannel中读取ByteBuffer,相关代码如下:
protected int doReadBytes(ByteBuf byteBuf) throws Exception {
return byteBuf.writeBytes(javaChannel(), byteBuf.writableBytes());
}
如果网络操作位为写,则说明有半包消息尚未发送完成,需要继续调用flush方法进行发送,相关代码如下:
if ((readyOps & SelectionKey.OP_WRITE) != 0) {
// Call forceFlush which will also take care of clear the OP_WRITE once there is nothing left to write
ch.unsafe().forceFlush();
}
如果网络操作位为连接状态,则需要对连接结果进行判读,如下:
if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
// remove OP_CONNECT as otherwise Selector.select(..) will always return without blocking
// See https://github.com/netty/netty/issues/924
int ops = k.interestOps();
ops &= ~SelectionKey.OP_CONNECT;
k.interestOps(ops);
unsafe.finishConnect();
}
需要注意的是,在进行finishConnect之前,需要将网络操作位进行修改,注销掉SelectionKey.OP_CONNECT。
处理完I/O事件后,NioEventLoop需要执行非I/O操作的系统Task和定时任务,代码如下:
final long ioTime = System.nanoTime() - ioStartTime;
final int ioRatio = this.ioRatio;
runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
由于NioEventLoop同时处理I/O事件和非I/O事件,Netty提供了两者的比例。 Task的执行时间根据本次I/O的执行时间得到,方法如下
fetchFromDelayedQueue();
Runnable task = pollTask();
if (task == null) {
return false;
}
首先从定时任务消息队列中弹出消息技能型处理,如果消息队列为空,则退出循环。根据当前的时间戳进行判断,如果该定时任务已经或者正处于超时状态,则将其加入到执行TaskQueue中,同时从延时队列中删除。定时任务如果没有超时,说明本循环不需要处理,直接退出即可,如下:
private void fetchFromDelayedQueue() {
long nanoTime = 0L;
for (;;) {
ScheduledFutureTask delayedTask = delayedTaskQueue.peek();
if (delayedTask == null) {
break;
}
if (nanoTime == 0L) {
nanoTime = ScheduledFutureTask.nanoTime();
}
if (delayedTask.deadlineNanos() <= nanoTime) {
delayedTaskQueue.remove();
taskQueue.add(delayedTask);
} else {
break;
}
}
}
执行Task Queue中原有的任务和从延时队列中复制的已经超时或者正处于超时状态的定时任务, 由于获取系统纳秒时间是个耗时的操作,每次循环都获取当前系统纳秒时间进行超时判断会降低性能。为了提升性能,每执行60次循环判断一次,如果当前系统已经到了分配给非I/O操作的超时时间,则退出循环。这是为了防止由于I/O操作过多导致I/O操作被长时间阻塞。
for (;;) {
try {
task.run();
} catch (Throwable t) {
logger.warn("A task raised an exception.", t);
}
runTasks ++;
// Check timeout every 64 tasks because nanoTime() is relatively expensive.
// XXX: Hard-coded value - will make it configurable if it is really a problem.
if ((runTasks & 0x3F) == 0) {
lastExecutionTime = ScheduledFutureTask.nanoTime();
if (lastExecutionTime >= deadline) {
break;
}
}
最后判断系统是否进入优雅停机状态,如果处于关闭状态,则需要调用closeAll方法释放资源,并让NioEventLoop线程退出循环,结束运行。关闭方法就在NioEventLoop的runAllTasks之后,进入其中,如下:
private void closeAll() {
selectAgain();
Set keys = selector.keys();
Collection channels = new ArrayList(keys.size());
for (SelectionKey k: keys) {
Object a = k.attachment();
if (a instanceof AbstractNioChannel) {
channels.add((AbstractNioChannel) a);
} else {
k.cancel();
@SuppressWarnings("unchecked")
NioTask task = (NioTask) a;
invokeChannelUnregistered(task, k, null);
}
}
for (AbstractNioChannel ch: channels) {
ch.unsafe().close(ch.unsafe().voidPromise());
}
}
遍历所有的channel,调用它的Unsafe.close()方法关闭所有链路,释放线程池,ChannelPipeline和ChannelHandler等资源。
你可能感兴趣的:(Netty源码分析之eventLoop和eventLoopGroup)
简单爬取一下电影排行
孟婆来包棒棒糖~
数据库 python 爬虫
主要用到了requests和xpath来解析数据,然后储存在mysql数据库中,不过代码方面我是先写好简单实现工作,然后让ai帮我用类封装来成功实现,博主比较菜,如果有反爬措施可以找js逆向视频来学习importrequestsfromfake_useragentimportUserAgentfromlxmlimportetreeimportpymysqlfrompymysql.cursorsim
昆仑通态-数据显示
创益无界
工业控制分享 数据库
我遇到一个问题,在上位机界面给设备设参数时,某一个参数的值大于一个常数时给不下去,我检查了数据类型没有问题,我在显示界面打开参数的属性设置面板,最大值设置没有问题。后发现在实时数据库对数据范围也做了限制昆仑通态有两个数据库:分别是设备窗口的数据库和实时数据库。设备窗口的数据库可以添加多个设备分别存储数据,对数据类型、数据长度等自由定义;实时数据库存储所有的数据,确保数据共享。设备窗口的数据库数据存
【Burp入门第三十六篇】加解密实现短信轰炸实战案例
秋说
Burp 漏洞挖掘
BurpSuite是一款功能强大的渗透测试工具,被广泛应用于Web应用程序的安全测试和漏洞挖掘中。本专栏将结合实操及具体案例,带领读者入门、掌握这款漏洞挖掘利器读者可订阅专栏:【Burp由入门到精通|CSDN秋说】文章目录背景加解密短信轰炸背景在针对目标应用程序的测试中,发现其密码找回功能存在请求加密机制,具体表现为用户通过手机号获取验证码的请求数据包采用了加密传输:加解密通
【Burp入门第三十三篇】BurpSuite+Proxifier安装配置,实现微信小程序抓包
秋说
BurpSuite 渗透工具 Proxifier
BurpSuite是一款功能强大的渗透测试工具,被广泛应用于Web应用程序的安全测试和漏洞挖掘中。本专栏将结合实操及具体案例,带领读者入门、掌握这款漏洞挖掘利器读者可订阅专栏:【Burp由入门到精通|CSDN秋说】文章目录下载配置下载汉化版下载地址:https://get-shell.com/1506.html#hidden-box-comment解压后双击exe文件:
C# 牵手DeepSeek:打造本地AI超能力
步、步、为营
c# 人工智能 开发语言
一、引言在人工智能飞速发展的当下,大语言模型如DeepSeek正掀起新一轮的技术变革浪潮,为自然语言处理领域带来了诸多创新应用。随着数据隐私和安全意识的提升,以及对模型部署灵活性的追求,本地部署DeepSeek成为众多开发者和企业关注的焦点。对于C#开发者而言,将DeepSeek模型本地部署并集成到C#项目中,不仅能充分发挥C#语言在Windows平台开发的优势,还能实现高度定制化的人工智能应用,
介绍下你们电商搜索的整体Java技术架构?
java1234_小锋
java java
大家好,我是锋哥。今天分享关于【介绍下你们电商搜索的整体Java技术架构?】面试题。希望对大家有帮助;介绍下你们电商搜索的整体Java技术架构?1000道互联网大厂Java工程师精选面试题-Java资源分享网在电商平台的搜索系统中,Java技术架构通常是构建高性能、可扩展、稳定搜索引擎的核心。一个典型的电商搜索系统通常会涉及以下几个关键部分:数据采集、索引建立、搜索查询处理、缓存和分布式处理等。下
Github-介绍
创益无界
嵌入式学习 github
GitHub是一个基于Git版本控制系统的代码托管平台,广泛用于开源项目、团队协作、代码管理等方面。它让开发者能够上传、分享、修改、协作、跟踪代码的更改。1.GitHub的基本功能:代码托管:GitHub提供云端存储代码的功能,可以方便开发者上传、下载和管理自己的代码。版本控制:通过Git进行版本管理,每次提交(commit)都会记录下代码的历史,方便回溯和协作。协作与分支管理:可以创建分支,开发
量化投资策略的生命周期:从设计到淘汰
云策量化
量化投资 自动化交易 程序化炒股 量化 炒股 miniQMT 量化交易 QMT 量化投资 deepseek
推荐阅读:《程序化炒股:如何申请官方交易接口权限?散户可以申请吗?》量化投资策略的生命周期:从设计到淘汰量化投资,这个听起来既神秘又充满科技感的领域,其实离我们并不遥远。它就像是金融市场中的“算法猎人”,通过数学模型和计算机程序来寻找投资机会。那么,一个量化投资策略是如何从无到有,再到最终被淘汰的呢?让我们一起探索这个策略的生命周期。1.策略的诞生:设计阶段1.1灵感的火花量化投资策略的诞生往往始
Windows 11 新增功能全解析:特性、使用与注意事项
xueyunshengling
微软精华知识宝箱 微软合作伙伴计划 windows 系统功能 Win11 Windows11新增功能
自Windows11发布以来,其一系列令人耳目一新的新增功能便吸引了众多用户的目光。相较于以往的Windows版本,Windows11在界面设计、性能优化以及功能拓展等方面均实现了重大变革。今天,就让我们一同深入探究Windows11的新增功能,详细了解它们的特性、使用方法以及使用过程中需要留意的事项。一、焕然一新的开始菜单与任务栏(一)功能特性居中布局设计:Windows11的开始菜单和任务栏默
【Java基础】Java 中 的`final` 关键字
李少兄
Java java 开发语言
前言在Java编程的世界里,final关键字是一个强大且常用的工具。它可以应用于类、方法和变量,赋予它们不同的“不可变”特性。一、final修饰类1.定义与特性当使用final修饰一个类时,这个类就如同被上了一把坚固的锁,不能被其他类继承,即不会有子类。这是Java语言精心设计的一种机制,目的是确保类的设计和实现不会被意外修改,从而保证类的行为和功能始终保持一致。2.示例代码//定义一个final
【Java基础】Java 中的枚举类
李少兄
Java java python 数据库
一、前言在Java编程中,枚举类(enum)是一个非常实用且强大的特性,自Java5引入以来,它为开发者提供了一种优雅的方式来表示一组固定的常量。枚举类主要用于信息标志和分类,能显著提升代码的可读性、可维护性和安全性。二、枚举类基础概念(一)枚举类的定义枚举类使用enum关键字来定义,它是一种特殊的类,用于封装一组固定的常量。以下是一个简单的示例:enumSeason{SPRING,SUMMER,
23道 K8S 面试题
奋斗喝咖啡
docker kubernetes 容器
1、k8s是什么?请说出你的了解?答:Kubernetes是一个针对容器应用,进行自动部署,弹性伸缩和管理的开源系统。主要功能是生产环境中的容器编排。K8S是Google公司推出的,它来源于由Google公司内部使用了15年的Borg系统,集结了Borg的精华。2、K8s架构的组成是什么?答:和大多数分布式系统一样,K8S集群至少需要一个主节点(Master)和多个计算节点(Node)。主节点主要
当我删除word文件时无法删除,提示:操作无法完成,因为已在Microsoft Word中打开
阿杜x
Word word
现象:查看电脑桌面下方的任务栏,明明已经关闭了WPS和WORD软件,但是打开word文档时还是提示:解决方法步骤:1、按一下键盘上的ctrl+Shift+Esc键打开任务管理器2、在进程中找到如下:快速找到的方法:点击进程界面中最上方的一个进程,然后把自己的电脑输入法切换为英文,然后,每按1️⃣次该进程名称开头字母M,就会跳转1次并找到下一个M开头的进程,直到找到如下进程:3、鼠标放在此进程上,右
前端21:Vue.js开发实践指南
mater lai
本文还有配套的精品资源,点击获取简介:Vue.js是前端开发领域流行的JavaScript框架,"前端21"项目展示了基于Vue.js的Web应用程序开发。本文详细介绍了Vue.js的核心概念、项目设置、npm脚本、自定义配置、文件结构、开发过程和VueCLI工具,以帮助开发者高效构建Web应用。1.Vue.js框架基础1.1Vue.js简介Vue.js是一套构建用户界面的渐进式JavaScrip
微软正则表达式库的实现与应用
江卓尔
本文还有配套的精品资源,点击获取简介:正则表达式是一种用于文本处理的强大工具,在Windows环境下微软提供了相应的支持。本项目涉及的微软正则表达式库可能是一个内部或第三方开发的框架,以C++实现。regexpr2.cpp和syntax2.cpp文件可能包含核心匹配算法和语法解析处理,而reimpl2.h、regexpr2.h和syntax2.h可能定义了实现细节、API接口和语法定义。resta
Windows Server 2016-Windows控制台的新增功能
weixin_34377065
控制台主机(支持所有字符模式的应用程序的基础代码,包括Windows命令提示符、WindowsPowerShell提示符等)已通过几种方式进行更新,以添加各种新功能。控制新功能新功能为默认启用,但可以通过"属性"界面(主要是在"选项"选项卡上)或使用这些注册表项(所有表项都是HKEY_CURRENT_USER\Console下的DWORD值)打开和关闭每个新功能或恢复到以前的控制台主机:注册表项说
软件测试24-紧跟时代步伐:微服务模式下API测试要怎么做?
程序员zhi路
软件工程&软件测试 微服务 架构 云原生
通过一个的RestfulAPI实例,我介绍了cURL和Postman工具的基本用法,这样我们对API测试有了一个感性认识;在此基础上,我介绍了API自动化测试框架发展的来龙去脉,借此我们对API测试框架的理解又更深入了一层。今天,我将更进一步,带你去了解当下最热门的技术领域的API测试,即微服务模式下的API测试。微服务架构下,API测试的最大挑战来自于庞大的测试用例数量,以及微服务之间的相互耦合
Python进程知多少
我的身前一尺是我的世界
Python python进程 python多进程 python进程共享内存 python服务器进程 python进程通信
目录目标Python版本官方文档概述进程(Process)的基本概念进程之间的通信方法进程同步进程间共享状态实战创建进程的基本语法创建进程并传递复杂的参数进程同步&进程通信共享内存基于服务器进程实现共享基于队列实现进程安全生产者&消费者模型(基于队列)生产者&消费者模型(基于管道)目标掌握进程的基本概念和使用方法,包括:创建进程、进程同步、进程间共享状态、进程通信。Python版本Python3.
Vue 路由基础:Vue 2 和 Vue 3 的比较与使用
念九_ysl
Vue vue.js 前端 javascript
Vue.js是一款非常流行的前端框架,而VueRouter是Vue.js的官方路由管理库。在前端开发中,路由是处理页面跳转和视图管理的关键部分。Vue2和Vue3都使用VueRouter来管理路由,但是随着Vue3的发布,VueRouter也有了不少变化。在本文中,我们将详细介绍Vue2和Vue3中的路由使用,比较它们之间的不同,并提供一些示例代码。一、安装VueRouter在Vue项目中使用Vu
网站快速收录与网站域名选择的关系分析
百度网站快速收录
百度网站快速收录 百度快速收录 网站快速收录 百度收录 网站收录
网站快速收录与网站域名选择之间存在密切的关系。以下是对这两者关系的详细分析:一、域名选择对网站快速收录的影响品牌匹配性:当域名能够直接反映品牌名称或核心业务内容时,有助于品牌形象的传播,并在用户心目中建立起清晰的品牌联想。这种匹配性可能使搜索引擎更容易理解网站的主题和内容,从而有助于网站的快速收录。关键词关联性:在域名中包含与业务相关的关键词,可能会提高网站在搜索引擎中的可见性。搜索引擎在识别网页
【Kubernetes】 Scheduler 的逻辑:从 Predicates/Priorities 到 Filter/Score
还没入门的大菜狗
kubernetes
Kubernetes调度框架的演进:从Predicates/Priorities到Filter/ScoreKubernetes调度框架从传统的Predicates(预选)和Priorities(优选)转变为现代的Filter和Score扩展点是在Kubernetes1.15到1.18这个时期逐步完成的。演进时间线Kubernetes1.15(2019年6月发布)首次引入调度框架(Schedulin
单点登录和普通登录的区别,来自百度AI的解释
mf_717714
前端
注意,以下回答均是百度AI伙伴回答,非博主的回答,仅供参考。1,什么是单点登录单点登录(SingleSignOn,简称SSO)是指在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。当用户在身份认证服务器上登录一次以后,即可获得访问单点登录系统中其他关联系统和应用软件的权限,同时这种实现不需要管理员对用户的登录状态或其他信息进行修改。2,单点登录有哪些实现方式?SSO的实现方式有
WPF的UserControl的MVVM模式赋值
观无
wpf
背景说明项目日常应用,经常会使用到UserConrol来进行组合形成组合控件,组合控件在使用过程中,必然需要进行赋值,当前案例是UserControl中label的定时赋值。技术分析1.分离关注点:MVVM模式将应用程序分为三个主要部分,即模型(Model)、视图(View)和视图模型(ViewModel)。在这个例子中,MyUserControlViewModel和MainViewModel充当
vue2学习笔记4 - 深入学习模板语法:插值语法和指令语法
我是飞鸟呀
Vue 学习 笔记 vue.js
前言在vue2学习笔记2-老规矩,从HelloWorld开始,了解Vue实例和模板-CSDN博客我们提到过,容器中的代码叫做Vue模板,它们遵循HTML规范,只是混入了特殊的Vue语法。这些特殊的Vue语法除了上一次我们提到的插值语法外,还有指令语法。插值语法,可以使用js表达式,读取vue实例data中的数据。但是能实现的功能比较单一,而且,也仅限于标签体中的文本替换。如果想要与元素的属性绑定,
自然语言处理:初识自然语言处理
梦丶晓羽
自然语言处理 人工智能
介绍大家好,博主又来给大家分享知识了。从这次开始,博主给大家分享自然语言处理这个领域的内容。这也是博主非常感兴趣的研究领域。最开始,博主计划在自然语言处理系列的第一篇博文中,和大家聊聊文本规范化这个话题。毕竟在自然语言处理领域里,文本规范化是一项基础且重要的工作,它能让原始文本变得更整齐有序,便于后续的处理分析。但转念一想,对于刚接触自然语言处理的小伙伴们来说,对于自然语言处理肯定会有些陌生。要是
进程基本概念和通信方式
Chasing追~
操作系统 websocket 信息与通信
进程基本概念-进程和子进程程序是计算机指令的集合,它以文件的形式存储在磁盘上,而**进程通常被定义为一个正在运行的程序的实例,是一个程序在其自身的地址空间中的一次执行活动.**一个程序可以对应多个进程.进程是资源申请,高度和独立运行的单位,因此,它使用系统中的运行资源,而程序不能申请系统资源,不能被系统高度也不能作为独立运行的单位,因此它不占系统运行资源.进程组成:操作系统用来管理进行的内核对象内
算法与数据结构(二叉树中的最大路径和)
a_j58
数据结构
题目思路这道题我们可以考虑用递归来解决。首先设计一个maxPath函数用来递归计算二叉树中一个节点的最大贡献值,具体来说,就是以该节点为根节点的子树中寻找以该节点为起点的一条路径,使得该路径上的节点值之和最大。如果该节点为空,则最大贡献值为0。如果非空,最大贡献值就等于节点值与其子节点中的最大贡献值之和过程分析假设二叉树如下递归步骤:1.节点20:左子树:空,leftGain=0。右子树:空,ri
k8s面试题总结(五)
a_j58
Kubernetes知识点汇总 kubernetes 容器 云原生
1.考虑一种情况,即公司希望通过维持最低成本来提高其效率和技术运营速度。您认为公司将如何实现这一目标?公司可以通过构建CI/CD管道来实现DevOps方法,但是这里可能出现的一个问题是配置可能需要一段时间才能启动并运行。因此,在实施CI/CD管道之后,公司的下一步应该是在云环境中工作。一旦他们开始处理云环境,他们就可以在集群上安排容器,并可以在Kubernetes的帮助下进行协调。这种方法将有助于
DeepSeek 开源狂欢周(四)DualPipe与EPLB双弹齐发,训练效率的“双引擎”加速器!
OpenCSG
开源 人工智能 社区 算法
在DeepSeek开源周的第四天,DualPipe和EPLB这两项全新技术一同亮相,它们不仅为DeepSeek的低成本、高效训练大模型提供了强大支持,还为全球AI爱好者和从业者送上了两份“技术大礼包”。这些创新技术展示了DeepSeek如何以600万美元成本,训练出能与GPT-4o、Claude3.5Sonnet等先进模型一较高下的顶级AI模型。DualPipe:管道气泡的“终结者”训练大模型时,
CVAT标注工具使用与功能测试-Windows下(保姆式教程)
Barry-mapping
docker 计算机视觉 windows
目录一、安装所需要环境1.1、项目介绍(项目下载地址)1.2、Vue环境配置1.3、配置docker(Windows下)二、CVAT安装和使用2.1、CVAT安装2.2、CVAT使用2.2.1、创建用户(account)2.2.2、基本选项设置(Settings)2.2.3、创建工程(Createanewproject)2.2.4、创建任务(Createanewtask)2.2.5、开始标注(St
矩阵求逆(JAVA)利用伴随矩阵
qiuwanchi
利用伴随矩阵求逆矩阵
package gaodai.matrix;
import gaodai.determinant.DeterminantCalculation;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* 矩阵求逆(利用伴随矩阵)
* @author 邱万迟
单例(Singleton)模式
aoyouzi
单例 模式 Singleton
3.1 概述 如果要保证系统里一个类最多只能存在一个实例时,我们就需要单例模式。这种情况在我们应用中经常碰到,例如缓存池,数据库连接池,线程池,一些应用服务实例等。在多线程环境中,为了保证实例的唯一性其实并不简单,这章将和读者一起探讨如何实现单例模式。 3.2
[开源与自主研发]就算可以轻易获得外部技术支持,自己也必须研发
comsci
开源
现在国内有大量的信息技术产品,都是通过盗版,免费下载,开源,附送等方式从国外的开发者那里获得的。。。。。。
虽然这种情况带来了国内信息产业的短暂繁荣,也促进了电子商务和互联网产业的快速发展,但是实际上,我们应该清醒的看到,这些产业的核心力量是被国外的
页面有两个frame,怎样点击一个的链接改变另一个的内容
Array_06
UI XHTML
<a src="地址" targets="这里写你要操作的Frame的名字" />搜索
然后你点击连接以后你的新页面就会显示在你设置的Frame名字的框那里
targerts="",就是你要填写目标的显示页面位置
=====================
例如:
<frame src=&
Struts2实现单个/多个文件上传和下载
oloz
文件上传 struts
struts2单文件上传:
步骤01:jsp页面
<!--在进行文件上传时,表单提交方式一定要是post的方式,因为文件上传时二进制文件可能会很大,还有就是enctype属性,这个属性一定要写成multipart/form-data,不然就会以二进制文本上传到服务器端-->
<form action="fileUplo
推荐10个在线logo设计网站
362217990
logo
在线设计Logo网站。
1、http://flickr.nosv.org(这个太简单)
2、http://www.logomaker.com/?source=1.5770.1
3、http://www.simwebsol.com/ImageTool
4、http://www.logogenerator.com/logo.php?nal=1&tpl_catlist[]=2
5、ht
jsp上传文件
香水浓
jsp fileupload
1. jsp上传
Notice:
1. form表单 method 属性必须设置为 POST 方法 ,不能使用 GET 方法
2. form表单 enctype 属性需要设置为 multipart/form-data
3. form表单 action 属性需要设置为提交到后台处理文件上传的jsp文件地址或者servlet地址。例如 uploadFile.jsp 程序文件用来处理上传的文
我的架构经验系列文章 - 前端架构
agevs
JavaScript Web 框架 UI jQuer
框架层面:近几年前端发展很快,前端之所以叫前端因为前端是已经可以独立成为一种职业了,js也不再是十年前的玩具了,以前富客户端RIA的应用可能会用flash/flex或是silverlight,现在可以使用js来完成大部分的功能,因此js作为一门前端的支撑语言也不仅仅是进行的简单的编码,越来越多框架性的东西出现了。越来越多的开发模式转变为后端只是吐json的数据源,而前端做所有UI的事情。MVCMV
android ksoap2 中把XML(DataSet) 当做参数传递
aijuans
android
我的android app中需要发送webservice ,于是我使用了 ksop2 进行发送,在测试过程中不是很顺利,不能正常工作.我的web service 请求格式如下
[html]
view plain
copy
<Envelope xmlns="http://schemas.
使用Spring进行统一日志管理 + 统一异常管理
baalwolf
spring
统一日志和异常管理配置好后,SSH项目中,代码以往散落的log.info() 和 try..catch..finally 再也不见踪影!
统一日志异常实现类:
[java]
view plain
copy
package com.pilelot.web.util;
impor
Android SDK 国内镜像
BigBird2012
android sdk
一、镜像地址:
1、东软信息学院的 Android SDK 镜像,比配置代理下载快多了。
配置地址, http://mirrors.neusoft.edu.cn/configurations.we#android
2、北京化工大学的:
IPV4:ubuntu.buct.edu.cn
IPV4:ubuntu.buct.cn
IPV6:ubuntu.buct6.edu.cn
HTML无害化和Sanitize模块
bijian1013
JavaScript AngularJS Linky Sanitize
一.ng-bind-html、ng-bind-html-unsafe
AngularJS非常注重安全方面的问题,它会尽一切可能把大多数攻击手段最小化。其中一个攻击手段是向你的web页面里注入不安全的HTML,然后利用它触发跨站攻击或者注入攻击。
考虑这样一个例子,假设我们有一个变量存
[Maven学习笔记二]Maven命令
bit1129
maven
mvn compile
compile编译命令将src/main/java和src/main/resources中的代码和配置文件编译到target/classes中,不会对src/test/java中的测试类进行编译
MVN编译使用
maven-resources-plugin:2.6:resources
maven-compiler-plugin:2.5.1:compile
&nbs
【Java命令二】jhat
bit1129
Java命令
jhat用于分析使用jmap dump的文件,,可以将堆中的对象以html的形式显示出来,包括对象的数量,大小等等,并支持对象查询语言。 jhat默认开启监听端口7000的HTTP服务,jhat是Java Heap Analysis Tool的缩写
1. 用法:
[hadoop@hadoop bin]$ jhat -help
Usage: jhat [-stack <bool&g
JBoss 5.1.0 GA:Error installing to Instantiated: name=AttachmentStore state=Desc
ronin47
进到类似目录 server/default/conf/bootstrap,打开文件 profile.xml找到: Xml代码<bean
name="AttachmentStore"
class="org.jboss.system.server.profileservice.repository.AbstractAtta
写给初学者的6条网页设计安全配色指南
brotherlamp
UI ui自学 ui视频 ui教程 ui资料
网页设计中最基本的原则之一是,不管你花多长时间创造一个华丽的设计,其最终的角色都是这场秀中真正的明星——内容的衬托
我仍然清楚地记得我最早的一次美术课,那时我还是一个小小的、对凡事都充满渴望的孩子,我摆放出一大堆漂亮的彩色颜料。我仍然记得当我第一次看到原色与另一种颜色混合变成第二种颜色时的那种兴奋,并且我想,既然两种颜色能创造出一种全新的美丽色彩,那所有颜色
有一个数组,每次从中间随机取一个,然后放回去,当所有的元素都被取过,返回总共的取的次数。写一个函数实现。复杂度是什么。
bylijinnan
java 算法 面试
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
/**
* http://weibo.com/1915548291/z7HtOF4sx
* #面试题#有一个数组,每次从中间随机取一个,然后放回去,当所有的元素都被取过,返回总共的取的次数。
* 写一个函数实现。复杂度是什么
struts2获得request、session、application方式
chiangfai
application
1、与Servlet API解耦的访问方式。
a.Struts2对HttpServletRequest、HttpSession、ServletContext进行了封装,构造了三个Map对象来替代这三种对象要获取这三个Map对象,使用ActionContext类。
----->
package pro.action;
import java.util.Map;
imp
改变python的默认语言设置
chenchao051
python
import sys
sys.getdefaultencoding()
可以测试出默认语言,要改变的话,需要在python lib的site-packages文件夹下新建:
sitecustomize.py, 这个文件比较特殊,会在python启动时来加载,所以就可以在里面写上:
import sys
sys.setdefaultencoding('utf-8')
&n
mysql导入数据load data infile用法
daizj
mysql 导入数据
我们常常导入数据!mysql有一个高效导入方法,那就是load data infile 下面来看案例说明
基本语法:
load data [low_priority] [local] infile 'file_name txt' [replace | ignore]
into table tbl_name
[fields
[terminated by't']
[OPTI
phpexcel导入excel表到数据库简单入门示例
dcj3sjt126com
PHP Excel
跟导出相对应的,同一个数据表,也是将phpexcel类放在class目录下,将Excel表格中的内容读取出来放到数据库中
<?php
error_reporting(E_ALL);
set_time_limit(0);
?>
<html>
<head>
<meta http-equiv="Content-Type"
22岁到72岁的男人对女人的要求
dcj3sjt126com
22岁男人对女人的要求是:一,美丽,二,性感,三,有份具品味的职业,四,极有耐性,善解人意,五,该聪明的时候聪明,六,作小鸟依人状时尽量自然,七,怎样穿都好看,八,懂得适当地撒娇,九,虽作惊喜反应,但看起来自然,十,上了床就是个无条件荡妇。 32岁的男人对女人的要求,略作修定,是:一,入得厨房,进得睡房,二,不必服侍皇太后,三,不介意浪漫蜡烛配盒饭,四,听多过说,五,不再傻笑,六,懂得独
Spring和HIbernate对DDM设计的支持
e200702084
DAO 设计模式 spring Hibernate 领域模型
A:数据访问对象
DAO和资源库在领域驱动设计中都很重要。DAO是关系型数据库和应用之间的契约。它封装了Web应用中的数据库CRUD操作细节。另一方面,资源库是一个独立的抽象,它与DAO进行交互,并提供到领域模型的“业务接口”。
资源库使用领域的通用语言,处理所有必要的DAO,并使用领域理解的语言提供对领域模型的数据访问服务。
NoSql 数据库的特性比较
geeksun
NoSQL
Redis 是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。目前由VMware主持开发工作。
1. 数据模型
作为Key-value型数据库,Redis也提供了键(Key)和值(Value)的映射关系。除了常规的数值或字符串,Redis的键值还可以是以下形式之一:
Lists (列表)
Sets
使用 Nginx Upload Module 实现上传文件功能
hongtoushizi
nginx
转载自: http://www.tuicool.com/wx/aUrAzm
普通网站在实现文件上传功能的时候,一般是使用Python,Java等后端程序实现,比较麻烦。Nginx有一个Upload模块,可以非常简单的实现文件上传功能。此模块的原理是先把用户上传的文件保存到临时文件,然后在交由后台页面处理,并且把文件的原名,上传后的名称,文件类型,文件大小set到页面。下
spring-boot-web-ui及thymeleaf基本使用
jishiweili
spring thymeleaf
视图控制层代码demo如下:
@Controller
@RequestMapping("/")
public class MessageController {
private final MessageRepository messageRepository;
@Autowired
public MessageController(Mes
数据源架构模式之活动记录
home198979
PHP 架构 活动记录 数据映射
hello!架构
一、概念
活动记录(Active Record):一个对象,它包装数据库表或视图中某一行,封装数据库访问,并在这些数据上增加了领域逻辑。
对象既有数据又有行为。活动记录使用直截了当的方法,把数据访问逻辑置于领域对象中。
二、实现简单活动记录
活动记录在php许多框架中都有应用,如cakephp。
<?php
/**
* 行数据入口类
*
Linux Shell脚本之自动修改IP
pda158
linux centos Debian 脚本
作为一名
Linux SA,日常运维中很多地方都会用到脚本,而服务器的ip一般采用静态ip或者MAC绑定,当然后者比较操作起来相对繁琐,而前者我们可以设置主机名、ip信息、网关等配置。修改成特定的主机名在维护和管理方面也比较方便。如下脚本用途为:修改ip和主机名等相关信息,可以根据实际需求修改,举一反三!
#!/bin/sh
#auto Change ip netmask ga
开发环境搭建
独浮云
eclipse jdk tomcat
最近在开发过程中,经常出现MyEclipse内存溢出等错误,需要重启的情况,好麻烦。对于一般的JAVA+TOMCAT项目开发,其实没有必要使用重量级的MyEclipse,使用eclipse就足够了。尤其是开发机器硬件配置一般的人。
&n
操作日期和时间的工具类
vipbooks
工具类
大家好啊,好久没有来这里发文章了,今天来逛逛,分享一篇刚写不久的操作日期和时间的工具类,希望对大家有所帮助。
/*
* @(#)DataFormatUtils.java 2010-10-10
*
* Copyright 2010 BianJing,All rights reserved.
*/
package test;
impor