@EnableAsync+@Async源码学习笔记之六
接上文,我们本文分析 AsyncExecutionAspectSupport
的源码:
package org.springframework.aop.interceptor;import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
import org.springframework.core.task.AsyncListenableTaskExecutor;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.core.task.support.TaskExecutorAdapter;
import org.springframework.lang.Nullable;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.concurrent.ListenableFuture;/*** Base class for asynchronous method execution aspects, such as* {@code org.springframework.scheduling.annotation.AnnotationAsyncExecutionInterceptor}* or {@code org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect}.** <p>Provides support for <i>executor qualification</i> on a method-by-method basis.* {@code AsyncExecutionAspectSupport} objects must be constructed with a default {@code* Executor}, but each individual method may further qualify a specific {@code Executor}* bean to be used when executing it, e.g. through an annotation attribute.** @author Chris Beams* @author Juergen Hoeller* @author Stephane Nicoll* @since 3.1.2*/
public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {/*** The default name of the {@link TaskExecutor} bean to pick up: "taskExecutor".* <p>Note that the initial lookup happens by type; this is just the fallback* in case of multiple executor beans found in the context.* @since 4.2.6*/public static final String DEFAULT_TASK_EXECUTOR_BEAN_NAME = "taskExecutor";protected final Log logger = LogFactory.getLog(getClass());private final Map<Method, AsyncTaskExecutor> executors = new ConcurrentHashMap<>(16);@Nullableprivate volatile Executor defaultExecutor;private AsyncUncaughtExceptionHandler exceptionHandler;@Nullableprivate BeanFactory beanFactory;/*** Create a new instance with a default {@link AsyncUncaughtExceptionHandler}.* @param defaultExecutor the {@code Executor} (typically a Spring {@code AsyncTaskExecutor}* or {@link java.util.concurrent.ExecutorService}) to delegate to, unless a more specific* executor has been requested via a qualifier on the async method, in which case the* executor will be looked up at invocation time against the enclosing bean factory*/public AsyncExecutionAspectSupport(@Nullable Executor defaultExecutor) {this(defaultExecutor, new SimpleAsyncUncaughtExceptionHandler());}/*** Create a new {@link AsyncExecutionAspectSupport} with the given exception handler.* @param defaultExecutor the {@code Executor} (typically a Spring {@code AsyncTaskExecutor}* or {@link java.util.concurrent.ExecutorService}) to delegate to, unless a more specific* executor has been requested via a qualifier on the async method, in which case the* executor will be looked up at invocation time against the enclosing bean factory* @param exceptionHandler the {@link AsyncUncaughtExceptionHandler} to use*/public AsyncExecutionAspectSupport(@Nullable Executor defaultExecutor, AsyncUncaughtExceptionHandler exceptionHandler) {this.defaultExecutor = defaultExecutor;this.exceptionHandler = exceptionHandler;}/*** Supply the executor to be used when executing async methods.* @param defaultExecutor the {@code Executor} (typically a Spring {@code AsyncTaskExecutor}* or {@link java.util.concurrent.ExecutorService}) to delegate to, unless a more specific* executor has been requested via a qualifier on the async method, in which case the* executor will be looked up at invocation time against the enclosing bean factory* @see #getExecutorQualifier(Method)* @see #setBeanFactory(BeanFactory)* @see #getDefaultExecutor(BeanFactory)*/public void setExecutor(Executor defaultExecutor) {this.defaultExecutor = defaultExecutor;}/*** Supply the {@link AsyncUncaughtExceptionHandler} to use to handle exceptions* thrown by invoking asynchronous methods with a {@code void} return type.*/public void setExceptionHandler(AsyncUncaughtExceptionHandler exceptionHandler) {this.exceptionHandler = exceptionHandler;}/*** Set the {@link BeanFactory} to be used when looking up executors by qualifier* or when relying on the default executor lookup algorithm.* @see #findQualifiedExecutor(BeanFactory, String)* @see #getDefaultExecutor(BeanFactory)*/@Overridepublic void setBeanFactory(BeanFactory beanFactory) {this.beanFactory = beanFactory;}/*** Determine the specific executor to use when executing the given method.* Should preferably return an {@link AsyncListenableTaskExecutor} implementation.* @return the executor to use (or {@code null}, but just if no default executor is available)*/@Nullableprotected AsyncTaskExecutor determineAsyncExecutor(Method method) {AsyncTaskExecutor executor = this.executors.get(method);if (executor == null) {Executor targetExecutor;String qualifier = getExecutorQualifier(method);if (StringUtils.hasLength(qualifier)) {targetExecutor = findQualifiedExecutor(this.beanFactory, qualifier);}else {System.out.println("使用默认的执行器");targetExecutor = this.defaultExecutor;if (targetExecutor == null) {synchronized (this.executors) {if (this.defaultExecutor == null) {this.defaultExecutor = getDefaultExecutor(this.beanFactory);}targetExecutor = this.defaultExecutor;}}}if (targetExecutor == null) {return null;}executor = (targetExecutor instanceof AsyncListenableTaskExecutor ?(AsyncListenableTaskExecutor) targetExecutor : new TaskExecutorAdapter(targetExecutor));this.executors.put(method, executor);}return executor;}/*** Return the qualifier or bean name of the executor to be used when executing the* given async method, typically specified in the form of an annotation attribute.* Returning an empty string or {@code null} indicates that no specific executor has* been specified and that the {@linkplain #setExecutor(Executor) default executor}* should be used.* @param method the method to inspect for executor qualifier metadata* @return the qualifier if specified, otherwise empty String or {@code null}* @see #determineAsyncExecutor(Method)* @see #findQualifiedExecutor(BeanFactory, String)*/@Nullableprotected abstract String getExecutorQualifier(Method method);/*** Retrieve a target executor for the given qualifier.* @param qualifier the qualifier to resolve* @return the target executor, or {@code null} if none available* @since 4.2.6* @see #getExecutorQualifier(Method)*/@Nullableprotected Executor findQualifiedExecutor(@Nullable BeanFactory beanFactory, String qualifier) {if (beanFactory == null) {throw new IllegalStateException("BeanFactory must be set on " + getClass().getSimpleName() +" to access qualified executor '" + qualifier + "'");}return BeanFactoryAnnotationUtils.qualifiedBeanOfType(beanFactory, Executor.class, qualifier);}/*** Retrieve or build a default executor for this advice instance.* An executor returned from here will be cached for further use.* <p>The default implementation searches for a unique {@link TaskExecutor} bean* in the context, or for an {@link Executor} bean named "taskExecutor" otherwise.* If neither of the two is resolvable, this implementation will return {@code null}.* @param beanFactory the BeanFactory to use for a default executor lookup* @return the default executor, or {@code null} if none available* @since 4.2.6* @see #findQualifiedExecutor(BeanFactory, String)* @see #DEFAULT_TASK_EXECUTOR_BEAN_NAME*/@Nullableprotected Executor getDefaultExecutor(@Nullable BeanFactory beanFactory) {if (beanFactory != null) {try {// Search for TaskExecutor bean... not plain Executor since that would// match with ScheduledExecutorService as well, which is unusable for// our purposes here. TaskExecutor is more clearly designed for it.return beanFactory.getBean(TaskExecutor.class);}catch (NoUniqueBeanDefinitionException ex) {logger.debug("Could not find unique TaskExecutor bean", ex);try {return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class);}catch (NoSuchBeanDefinitionException ex2) {if (logger.isInfoEnabled()) {logger.info("More than one TaskExecutor bean found within the context, and none is named " +"'taskExecutor'. Mark one of them as primary or name it 'taskExecutor' (possibly " +"as an alias) in order to use it for async processing: " + ex.getBeanNamesFound());}}}catch (NoSuchBeanDefinitionException ex) {logger.debug("Could not find default TaskExecutor bean", ex);try {return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class);}catch (NoSuchBeanDefinitionException ex2) {logger.info("No task executor bean found for async processing: " +"no bean of type TaskExecutor and no bean named 'taskExecutor' either");}// Giving up -> either using local default executor or none at all...}}return null;}/*** Delegate for actually executing the given task with the chosen executor.* @param task the task to execute* @param executor the chosen executor* @param returnType the declared return type (potentially a {@link Future} variant)* @return the execution result (potentially a corresponding {@link Future} handle)*/@Nullableprotected Object doSubmit(Callable<Object> task, AsyncTaskExecutor executor, Class<?> returnType) {if (CompletableFuture.class.isAssignableFrom(returnType)) {return CompletableFuture.supplyAsync(() -> {try {System.out.println("最终调用方法的地方");return task.call();}catch (Throwable ex) {throw new CompletionException(ex);}}, executor);}else if (ListenableFuture.class.isAssignableFrom(returnType)) {System.out.println("最终调用方法的地方");return ((AsyncListenableTaskExecutor) executor).submitListenable(task);}else if (Future.class.isAssignableFrom(returnType)) {System.out.println("最终调用方法的地方");return executor.submit(task);}else {System.out.println("最终调用方法的地方");executor.submit(task);return null;}}/*** Handles a fatal error thrown while asynchronously invoking the specified* {@link Method}.* <p>If the return type of the method is a {@link Future} object, the original* exception can be propagated by just throwing it at the higher level. However,* for all other cases, the exception will not be transmitted back to the client.* In that later case, the current {@link AsyncUncaughtExceptionHandler} will be* used to manage such exception.* @param ex the exception to handle* @param method the method that was invoked* @param params the parameters used to invoke the method*/protected void handleError(Throwable ex, Method method, Object... params) throws Exception {if (Future.class.isAssignableFrom(method.getReturnType())) {ReflectionUtils.rethrowException(ex);}else {// Could not transmit the exception to the caller with default executortry {this.exceptionHandler.handleUncaughtException(ex, method, params);}catch (Throwable ex2) {logger.error("Exception handler for async method '" + method.toGenericString() +"' threw unexpected exception itself", ex2);}}}}
我们主要看2个方法:determineAsyncExecutor
和 doSubmit
。
- 先看
determineAsyncExecutor
@Nullable
protected AsyncTaskExecutor determineAsyncExecutor(Method method) {AsyncTaskExecutor executor = this.executors.get(method);if (executor == null) {Executor targetExecutor;String qualifier = getExecutorQualifier(method);if (StringUtils.hasLength(qualifier)) {targetExecutor = findQualifiedExecutor(this.beanFactory, qualifier);}else {System.out.println("使用默认的执行器");targetExecutor = this.defaultExecutor;if (targetExecutor == null) {synchronized (this.executors) {if (this.defaultExecutor == null) {this.defaultExecutor = getDefaultExecutor(this.beanFactory);}targetExecutor = this.defaultExecutor;}}}if (targetExecutor == null) {return null;}executor = (targetExecutor instanceof AsyncListenableTaskExecutor ?(AsyncListenableTaskExecutor) targetExecutor : new TaskExecutorAdapter(targetExecutor));this.executors.put(method, executor);}return executor;
}
首先,调用 getExecutorQualifier
方法,作用是获取线程池的名字,这是个抽象方法,子类 AnnotationAsyncExecutionInterceptor
中有实现,我们在前面的文章也讲过了,这里再简单看下源码:
@Override
@Nullable
protected String getExecutorQualifier(Method method) {// Maintainer's note: changes made here should also be made in// AnnotationAsyncExecutionAspect#getExecutorQualifierAsync async = AnnotatedElementUtils.findMergedAnnotation(method, Async.class);if (async == null) {async = AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), Async.class);}System.out.println("找 @Async 注解。先找方法上的。找不到的话再找类上的。也就是说方法上的@Async注解的优先级要高于类上的。");return (async != null ? async.value() : null);
}
然后,调用 findQualifiedExecutor
方法,作用是根据上一步找到的线程池的名字,从容器中找对应的线程池,如下:
@Nullable
protected Executor findQualifiedExecutor(@Nullable BeanFactory beanFactory, String qualifier) {if (beanFactory == null) {throw new IllegalStateException("BeanFactory must be set on " + getClass().getSimpleName() +" to access qualified executor '" + qualifier + "'");}return BeanFactoryAnnotationUtils.qualifiedBeanOfType(beanFactory, Executor.class, qualifier);
}
接着,如果没找到线程池的话,使用默认的线程池,代码如下,这里用到的是双重加锁检查
targetExecutor = this.defaultExecutor;
if (targetExecutor == null) {synchronized (this.executors) {if (this.defaultExecutor == null) {this.defaultExecutor = getDefaultExecutor(this.beanFactory);}targetExecutor = this.defaultExecutor;}
}
重点看下这个 getDefaultExecutor
方法,源码如下:
@Nullable
protected Executor getDefaultExecutor(@Nullable BeanFactory beanFactory) {if (beanFactory != null) {try {// Search for TaskExecutor bean... not plain Executor since that would// match with ScheduledExecutorService as well, which is unusable for// our purposes here. TaskExecutor is more clearly designed for it.return beanFactory.getBean(TaskExecutor.class);}catch (NoUniqueBeanDefinitionException ex) {logger.debug("Could not find unique TaskExecutor bean", ex);try {return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class);}catch (NoSuchBeanDefinitionException ex2) {if (logger.isInfoEnabled()) {logger.info("More than one TaskExecutor bean found within the context, and none is named " +"'taskExecutor'. Mark one of them as primary or name it 'taskExecutor' (possibly " +"as an alias) in order to use it for async processing: " + ex.getBeanNamesFound());}}}catch (NoSuchBeanDefinitionException ex) {logger.debug("Could not find default TaskExecutor bean", ex);try {return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class);}catch (NoSuchBeanDefinitionException ex2) {logger.info("No task executor bean found for async processing: " +"no bean of type TaskExecutor and no bean named 'taskExecutor' either");}// Giving up -> either using local default executor or none at all...}}return null;
}
代码看着挺长的,其实不然,关键就是下面这一句:
beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class);
再看下默认的线程池的名字 DEFAULT_TASK_EXECUTOR_BEAN_NAME
的定义:
/*** The default name of the {@link TaskExecutor} bean to pick up: "taskExecutor".* <p>Note that the initial lookup happens by type; this is just the fallback* in case of multiple executor beans found in the context.* @since 4.2.6*/
public static final String DEFAULT_TASK_EXECUTOR_BEAN_NAME = "taskExecutor";
看到了吧,默认的用于执行异步任务的线程池的名字就是 taskExecutor
。
接着往下看:
if (targetExecutor == null) {return null;
}
executor = (targetExecutor instanceof AsyncListenableTaskExecutor ?(AsyncListenableTaskExecutor) targetExecutor : new TaskExecutorAdapter(targetExecutor));
this.executors.put(method, executor);
如果没找到线程池,就返回 null ;如果找到了,判断类型是不是 AsyncListenableTaskExecutor
,是的话就直接返回,不是的话就用 TaskExecutorAdapter
包一下。这个地方不细讲了。有兴趣可以自己研究下 AsyncListenableTaskExecutor
和 TaskExecutorAdapter
。
- 然后就是看
doSubmit
方法了
@Nullable
protected Object doSubmit(Callable<Object> task, AsyncTaskExecutor executor, Class<?> returnType) {if (CompletableFuture.class.isAssignableFrom(returnType)) {return CompletableFuture.supplyAsync(() -> {try {System.out.println("最终调用方法的地方");return task.call();}catch (Throwable ex) {throw new CompletionException(ex);}}, executor);}else if (ListenableFuture.class.isAssignableFrom(returnType)) {System.out.println("最终调用方法的地方");return ((AsyncListenableTaskExecutor) executor).submitListenable(task);}else if (Future.class.isAssignableFrom(returnType)) {System.out.println("最终调用方法的地方");return executor.submit(task);}else {System.out.println("最终调用方法的地方");executor.submit(task);return null;}
}
这里边对返回值进行了判断,根据返回值的不同,走不同的分支,不管哪个分支,最终都是把任务交给了线程池。
至此,本系列文章结束。
相关文章:
@EnableAsync+@Async源码学习笔记之六
接上文,我们本文分析 AsyncExecutionAspectSupport 的源码: package org.springframework.aop.interceptor;import java.lang.reflect.Method; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.CompletableFu…...
SQL系列:常用函数
1、【MySQL】合并字段函数(列转行) 它可以将两个字段中的数据合并到一个字段中。 1)CONCAT函数 CONCAT函数可以将多个字段中的数据合并到一个字段中。它的语法格式如下: SELECT CONCAT(字段1,字段2,...字段N) FROM 表名;SELEC…...
Git 中修改某个特定的commit提交内容
在 Git 中修改某个特定的提交(commit)通常需要使用 交互式变基(Interactive Rebase) 或 修改提交(Commit Amend)。以下是不同场景下的具体操作步骤: 一、修改最近的提交(最新提交&am…...
FHS --- linux目录结构(部分目录解释)
根目录(/) 的意义和内容 : 根目录是整个系统最重要的一个目录,因为不但所有的目录都是由根目录衍生出来的,同时根目录也与开机/还原/系统修复等动作有关 。 由于系统开机时需要特定的开机软件、核心档案、开机所需程序…...
不带无线网卡的Linux开发板上网方法
I.MX6ULL通过网线上网 设置WLAN共享修改开发板的IP 在使用I.MX6ULL-MINI开发板学习Linux的时候,有时需要更新或者下载一些资源包,但是开发板本身是不带无线网卡或者WIFI芯片的,尝试使用网口连接笔记本,笔记本通过无线网卡连接WIFI…...
图书管理系统C语言
图书管理系统C语言代码示例。 该系统可以实现图书信息(包含图书编号、书名、作者、出版社、价格、库存数量)的录入、显示、查询、修改、删除等功能,还具备一定的错误处理和输入验证。 #include <stdio.h> #include <stdlib.h> …...
关于大型语言模型的“生物学”
我知道我们已经聊过很多次,关于LLM是怎么运作的,它们的影响力,还有它们的使用场景。但尽管现在有那么多讲LLM的文章,它们本质上还是个黑箱。 但我们真正要问自己的问题是,为什么理解这些系统的内部结构很重要…...
图像预处理-图像边缘检测(流程)
一.高斯滤波 因为图像边缘检测就是把像素值有差异的地方提取出来,所以噪声会有很大影响,因此需要对图像进行平滑处理,高斯滤波是流程中常用的方法。 二.计算图像的梯度与方向 过程中通常使用sobel算子进行梯度计算,在OpenCV中&am…...
解锁思想道德修养的奥秘:用思维导图开启智慧之旅
在我们的成长过程中,思想道德修养如同基石,奠定了我们为人处世、面对生活挑战的基本态度和准则。而如何高效地梳理和掌握思想道德修养的丰富内容呢?思维导图这一强大工具为我们提供了独特视角和便捷途径。 思想道德修养的关键板块 道德理论…...
swagger的简介及使用方法
Swagger 是一个用于描述、生成、文档化和测试 RESTful API 的开源工具集。它可以自动生成 API 文档,帮助开发者理解和使用 API。Swagger 由 Swagger.io 提供,并已经发展成了一套广泛应用于 API 设计和文档的标准。 Swagger 项目的历史可以追溯到 2010 年…...
解决Ubuntu图形化界面操作适配问题
1 缘起 使用Ubuntu GNOME图形化系统作为开发机, 遇到与Windows操作不一致的地方,比如PyCharm、IntelliJ时无法正确代码跳转, 如CtrlAltLeft,CtrlAltRight无法正常在代码级别跳转,只能在文件级别跳转。 基于这个开端&a…...
End-to-End从混沌到秩序:基于LLM的Pipeline将非结构化数据转化为知识图谱
摘要:本文介绍了一种将非结构化数据转换为知识图谱的端到端方法。通过使用大型语言模型(LLM)和一系列数据处理技术,我们能够从原始文本中自动提取结构化的知识。这一过程包括文本分块、LLM 提示设计、三元组提取、归一化与去重,最终利用 NetworkX 和 ipycytoscape 构建并可…...
使用Ingress发布应用程序
使用Ingress发布应用程序 文章目录 使用Ingress发布应用程序[toc]一、什么是Ingress二、定义Ingress三、什么是Ingress控制器四、部署nginx Ingress控制器1.了解nginx Ingress控制器的部署方式2.安装nginx Ingress控制器3.本地实际测试 五、使用Ingress对外发布应用程序1.使用D…...
llama-factory微调报错:
报错信息 [INFO] [utils.py:789:see_memory_usage] CPU Virtual Memory: used 81.51 GB, percent 64.9% W0419 10:14:27.573000 108354 site-packages/torch/distributed/elastic/multiprocessing/api.py:897] Sending process 108373 closing signal SIGTERM W0419 10:14:27…...
【LLaMAFactory】LoRa + 魔搭 微调大模型实战
前言 环境准备 之前是在colab上玩,这次在国内的环境上玩玩。 魔搭:https://www.modelscope.cn/ 现在注册,有100小时的GPU算力使用。注册好了之后: 魔搭社区 这里使用qwen2.5-7B-Instruct模型,这里后缀Instruct是指…...
【愚公系列】《Python网络爬虫从入门到精通》054-Scrapy 文件下载
🌟【技术大咖愚公搬代码:全栈专家的成长之路,你关注的宝藏博主在这里!】🌟 📣开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主! …...
db中查询关于null的sql该怎么写
正确示例 # 等于null select * from 表名 where 字段名 is NULL; # 不等于null select * from 表名 where 字段名 is not NULL;若需要同时判断字段不等于某个值且不为null select * from users where age ! 30 and age is not null; select * from users where age ! 30 or a…...
React 文章列表
自定义hook 在src/hooks文件夹下封装 useChannel.js // 获取频道列表的逻辑 import { useEffect , useState } from "react" import { getChannelAPI } from "/apis/article"function useChannel(){// 获取频道的逻辑 const [channelList,setChannelList…...
中间件--ClickHouse-12--案例-1-日志分析和监控
1、案例背景 一家互联网公司需要实时分析其服务器日志、应用日志和用户行为日志,以快速发现潜在问题并优化系统性能。 2、需求分析 目标:实时分析日志数据,快速发现问题并优化系统性能。数据来源: 服务器日志:如 Ng…...
QML中的3D功能--自定义着色器开发
在 Qt 3D 中使用自定义着色器可以实现高度定制化的渲染效果。以下是完整的自定义着色器开发方案。 一、基础着色器创建 1. 创建自定义材质 qml import Qt3D.Core 2.15 import Qt3D.Render 2.15 import Qt3D.Extras 2.15Entity {components: [Transform { translation: Qt.v…...
如何防止接口被刷
目录 🛡️ 一、常见的防刷策略分类 🔧 二、技术实现细节 ✅ 1. 基于 IP 限流 ✅ 2. 给接口加验证码 ✅ 3. 使用 Token 限制接口访问权限 ✅ 4. 给接口加冷却时间(验证码类经典) ✅ 5. 使用滑动窗口限流算法(更精…...
18、TimeDiff论文笔记
TimeDiff **1. 背景与动机****2. 扩散模型基础****3. TimeDiff 模型****3.1 前向扩散过程****3.2 后向去噪过程** 4、TimeDiff(架构)原理训练推理其他关键点解释 DDPM(相关数学)1、正态分布2、条件概率1. **与多个条件相关**&…...
docker底层原理
一句话,dockerfile里面的一行指令,就是一个layer层 docker底层原理 在机器上安装docker服务器端的程序,就会在机器上自动创建以下目录,默认安装路径是/var/lib/ docker服务器端的工作目录的作用如下,镜像的每一层的元数…...
YOLO拓展-NMS算法
1.概述 NMS(non maximum suppression)即非极大值抑制,其本质就是搜索局部极大值,抑制非极大值元素,可以理解为局部最大搜索。 这里不讨论通用的NMS算法(参考论文《Efficient Non-Maximum Suppression》对1维和2维数据…...
Docker Swarm 容器与普通 Docker 容器的网卡差异
问题背景 在 Docker Swarm 网络空间启动的容器有两张网卡(eth0 和 eth1),而普通 Docker 容器只有一张网卡(eth0)。以下通过分析 ip addr show 和 ip link show 的输出,解释原因。 命令输出解析 Docker S…...
【Linux】线程ID、线程管理、与线程互斥
📚 博主的专栏 🐧 Linux | 🖥️ C | 📊 数据结构 | 💡C 算法 | 🌐 C 语言 上篇文章: 【Linux】线程:从原理到实战,全面掌握多线程编程!-CSDN博客 下…...
服务器简介(含硬件外观接口介绍)
服务器(Server)是指提供资源、服务、数据或应用程序的计算机系统或设备。它通常比普通的个人计算机更强大、更可靠,能够长时间无间断运行,支持多个用户或客户端的请求。简单来说,服务器就是专门用来存储、管理和提供数…...
自动驾驶---决策规划之导航增强端到端
1 背景 自动驾驶算法通常包括几个子任务,包括3D物体检测、地图分割、运动预测、3D占用预测和规划。近年来,端到端方法将多个独立任务整合到多任务学习中,优化整个系统,包括中间表示,以实现最终的规划任务。随着端到端技…...
Datawhale AI春训营 世界科学智能大赛--合成生物赛道:蛋白质固有无序区域预测 小白经验总结
一、报名大赛 二、跑通baseline 在魔塔社区创建实例,根据教程完成速通第一个分数~ Datawhale-学用 AI,从此开始 三、优化实例(这里是我的学习优化过程) 1.先将官方给的的模型训练实例了解一遍(敲一敲代码) 训练模…...
基于Java(Struts2 + Hibernate + Spring)+MySQL实现的(Web)在线预约系统
基于Struts2 Hibernate Spring的在线预约系统 1.引言 1.1编写目的 针对医院在线预约挂号系统,提供详细的设计说明,包括系统的需求、功能模块、界面设计、设计方案等,以辅助开发人员顺利进行系统的开发并让项目相关者可以对这个系统进行分…...
PHP获取大文件行数
在PHP中获取大文件的行数时,直接读取整个文件到内存中可能会导致内存溢出,特别是对于非常大的文件。因此,最有效的方法是逐行读取文件并计数。以下是一些实现方法: 方法一:使用 fgets() fgets() 函数逐行读取文件&am…...
2024年网站开发语言选择指南:PHP/Java/Node.js/Python如何选型?
2024年网站开发语言选择指南:PHP/Java/Node.js/Python如何选型? 一、8大主流Web开发语言技术对比 1. PHP开发:中小型网站的首选方案 最新版本:PHP 8.3(2023年11月发布)核心优势: 全球78%的网站…...
Win7模拟器2025中文版:重温经典,掌上电脑体验
随着科技的快速发展,现代操作系统变得越来越高级,但许多用户仍然怀念经典的Windows 7系统。如果你也想重温那种熟悉的操作体验,Win7模拟器2025中文版 是一个不错的选择。这款软件能够让你在手机上轻松实现Windows 7系统的模拟,带来…...
HTML5+CSS3小实例:CSS立方体
实例:CSS立方体 技术栈:HTML+CSS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0&q…...
使用 Vite 快速搭建现代化 React 开发环境
1.检查环境 说明:检测环境,node版本为18.20.6。 2.创建命令 说明:创建命令,选择对应的选项。 npm create vitelatest 3.安装依赖 说明:安装相关依赖。 npm i...
Linux网络编程——基于ET模式下的Reactor
一、前言 上篇文章中我们已经讲解了多路转接剩下的两个接口:poll和epoll,并且知道了epoll的两种工作模式分别是 LT模式和ET模式,下来我们就实现的是一个简洁版的 Reactor,即半同步半异步I/O,在linux网络中,…...
【现代深度学习技术】循环神经网络04:循环神经网络
【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈PyTorch深度学习 ⌋ ⌋ ⌋ 深度学习 (DL, Deep Learning) 特指基于深层神经网络模型和方法的机器学习。它是在统计机器学习、人工神经网络等算法模型基础上,结合当代大数据和大算力的发展而发展出来的。深度学习最重…...
1. 认识DartGoogle为Flutter选择了Dart语言已经是既
1. 认识Dart Google为Flutter选择了Dart语言已经是既定的事实,无论你多么想用你熟悉的语言,比如JavaScript、TypeScript、ArkTS等来开发Flutter,至少目前都是不可以的。 Dart 是由谷歌开发的计算机编程语言,它可以被应用于 Web/…...
学习设计模式《三》——适配器模式
一、基础概念 适配器模式的本质是【转换匹配,复用功能】; 适配器模式定义:将一个类的接口转换为客户希望的另外一个接口;适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 适配器模式的目的:复用…...
【Java面试系列】Spring Boot微服务架构下的分布式事务处理与性能优化 - 2025-04-19详解 - 3-5年Java开发必备知识
【Java面试系列】Spring Boot微服务架构下的分布式事务处理与性能优化 - 2025-04-19详解 - 3-5年Java开发必备知识 引言 在微服务架构中,分布式事务处理和性能优化是面试中高频出现的主题。随着系统规模的扩大,如何保证数据一致性和系统性能成为开发者…...
Elasticsearch只返回指定的字段(用_source)
在Elasticsearch中,当你想要查询文档但不返回所有字段,只返回指定的字段(比如这里的id字段),你可以使用_source参数来实现这一点。但是,有一点需要注意:Elasticsearch的_source字段默认是返回的…...
【Linux “sed“ 命令详解】
本章目录: 1. 命令简介sed 的优势: 2. 命令的基本语法和用法基本语法:参数说明:常见用法场景:示例1:替换文本示例2:删除空行示例3:从命令输出中处理内容 3. 命令的常用选项及参数常用命令动作&a…...
JMETER使用
接口测试流程: 1.获取接口文档,熟悉接口业务 2.编写接口测试用例以及评审 正例:输入正常的参数,验证接口能否正常返回 反例:权限异常(为空、错误、过期)、参数异常(为空、长度异常、类型异常)、其他异常(黑名单、调用次数限制)、兼容异常(一个接口被多种…...
JavaWeb 课堂笔记 —— 13 MySQL 事务
本系列为笔者学习JavaWeb的课堂笔记,视频资源为B站黑马程序员出品的《黑马程序员JavaWeb开发教程,实现javaweb企业开发全流程(涵盖SpringMyBatisSpringMVCSpringBoot等)》,章节分布参考视频教程,为同样学习…...
离线安装elasticdump并导入和导出数据
离线安装elasticdump 在 CentOS 或 RHEL 系统上安装 elasticdump,你可以使用 npm(Node.js 的包管理器)来安装,因为 elasticdump 是一个基于 Node.js 的工具。以下是步骤 先在外网环境下安装 下载nodejs和npm(注意x8…...
WhatTheDuck:一个基于浏览器的CSV查询工具
今天给大家介绍一个不错的小工具:WhatTheDuck。它是一个免费开源的 Web 应用程序,允许用户上传 CSV 文件并针对其内容执行 SQL 查询分析。 WhatTheDuck 支持 SQL 代码自动完成以及语法高亮。 WhatTheDuck 将上传的数据存储为 DuckDB 内存表,继…...
关于数字信号与图像处理——基于Matlab的图像增强技术
本篇博客是在做数字信号与图像处理实验中的收获。 具体内容包括:根据给定的代码放入Matlab中分别进行两次运行测试——比较并观察运行后的实验结果与原图像的不同点——画出IJ的直方图,并比较二者差异。接下来会对每一步进行具体讲解。 题目:…...
MySQL数据库 - 锁
锁 此笔记参考黑马教程,仅学习使用,如有侵权,联系必删 文章目录 锁1. 概述1.1 介绍1.2 分类 2. 全局锁2.1 介绍2.2 语法2.3 特点(弊端) 3. 表级锁3.1 介绍3.2 表锁3.3 元数据锁(meta data lock࿰…...
免费多平台运行器,手机畅玩经典主机大作
软件介绍 飞鸟模拟器是一款面向安卓设备的免费游戏平台,支持PS2/PSP/NDS等十余种经典主机游戏运行。 该软件突破传统模拟器复杂操作模式,采用智能核心加载技术,用户只需双击主程序即可开启游戏之旅,真正实现"即下即玩"…...
计算机软考中级 知识点记忆——排序算法 冒泡排序-插入排序- 归并排序等 各种排序算法知识点整理
一、📌 分类与比较 排序算法 最优时间复杂度 平均时间复杂度 最坏时间复杂度 空间复杂度 稳定性 应用场景与特点 算法策略 冒泡排序 O(n) O(n) O(n) O(1) 稳定 简单易实现,适用于小规模数据排序。 交换排序策略 插入排序 O(n) O(n) O…...