@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…...
Java CMS和G1垃圾回收器
举个真带劲的例子:把JVM内存比作你家的祖传旱厕 想象你有个祖传旱厕,分三个坑: 新坑区(年轻代):刚拉的屎热乎着(新对象)陈年坑(老年代):风干的屎…...
Vue+Notification 自定义消息通知组件 支持数据分页 实时更新
效果图: message.vue 消息组件 子组件 <template><div class"custom-notification"><div class"content"><span click"gotoMessageList(currentMessage.split()[1])">{{ currentMessage.split()[0] }}</…...
不规则曲面上两点距离求取
背景 在CT中求皮肤上两点间的弧长。由于人体表面并不是规则的曲面,不可能用圆的弧长求取方法来计算出两点间的弧长。 而在不规则的曲面上求两点的距离,都可以用类似测地线距离求取的方式来求取(积分),而转化为搜索路…...
Redis面试问题缓存相关详解
Redis面试问题缓存相关详解 一、缓存三兄弟(穿透、击穿、雪崩) 1. 穿透 问题描述: 缓存穿透是指查询一个数据库中不存在的数据,由于缓存不会保存这样的数据,每次都会穿透到数据库,导致数据库压力增大。例…...
性能比拼: Elixir vs Go
本内容是对知名性能评测博主 Anton Putra Elixir vs Go (Golang) Performance (Latency - Throughput - Saturation - Availability) 内容的翻译与整理, 有适当删减, 相关指标和结论以原作为准 对比 Elixir 和 Go 简介 许多人长期以来一直要求我对比 Elixir 和 Go。在本视频…...
精益数据分析(6/126):深入理解精益分析的核心要点
精益数据分析(6/126):深入理解精益分析的核心要点 在创业和数据驱动的时代浪潮中,我们都在不断探索如何更好地利用数据推动业务发展。我希望通过和大家分享对《精益数据分析》的学习心得,一起在这个充满挑战和机遇的领…...
【Linux网络与网络编程】11.数据链路层mac帧协议ARP协议
前面在介绍网络层时我们提出来过一个问题:主机是怎么把数据交给路由器的?那里我们说这是由数据链路层来做的。 网络上的报文在物理结构上是以mac帧的形式流动的,但在逻辑上是以IP流动的,IP的流动是需要mac帧支持的。 数据链路层解…...
JAVA设计模式:注解+模板+接口
1.基础组件 1.1注解类控制代码执行启动、停止、顺序 /*** author : test* description : 数据同步注解* date : 2025/4/18*/ Target({ElementType.TYPE}) Retention(RetentionPolicy.RUNTIME) Documented public interface SyncMeta {/*** 执行服务名称* return*/String name…...
Linux系统编程 day6 进程间通信mmap
父子共享的信息:文件描述符,mmap建立的共享映射区(MAP_SHARED) mmap父子间进程通信 var的时候 :读时共享,写时复制 父进程先创建映射区,指定共享MAP_SHARED权限 , fork创建子进程…...
【MySQL】MySQL建立索引不知道注意什么?
基本原则: 1.选择性原则: 选择高选择性的列建立索引(该列有大量不同的值) 2.适度原则:不是越多越好,每个索引都会增加写入开销 列选择注意事项: 1.常用查询条件列:WHERE字句中频繁使用的列 2.连接操作列…...
定制一款国密浏览器(9):SM4 对称加密算法
上一章介绍了 SM3 算法的移植要点,本章介绍对称加密算法 SM4 的移植要点。 SM4 算法相对 SM3 算法来说复杂一些,但还是比较简单的算法,详细算法说明参考《GMT 0002-2012 SM4分组密码算法》这份文档。铜锁开源项目的实现代码在 sm4.c 文件中,直接拿过来编译就可以。 但需要…...
Redis 的持久化机制(RDB, AOF)对微服务的数据一致性和恢复性有何影响?如何选择?
Redis 的持久化机制(RDB 和 AOF)对于保证 Redis 服务重启或崩溃后数据的恢复至关重要,这直接影响到依赖 Redis 的微服务的数据一致性和恢复能力。 1. RDB (Redis Database Backup) 机制: 在指定的时间间隔内,将 Redis 在内存中的…...
lottie深入玩法
A、json文件和图片资源分开 delete 是json资源名字 /res/lottie/delete_anim_images是图片资源文件夹路径 JSON 中引用的图片名,必须与实际图片文件名一致 B、json文件和图片资源分开,并且图片加载不固定 比如我有7张图片,分别命名1~7&…...
Android学习总结之算法篇七(图和矩阵)
有向图的深度优先搜索(DFS)和广度优先搜索(BFS)的示例,以此来模拟遍历 GC Root 引用链这种有向图结构: 一、深度优先搜索(DFS) import java.util.*;public class GraphDFS {privat…...
docker 大模型
使用 Docker 实现大模型的步骤指南 在今天的文章中,我们将指导刚入行的小白如何使用 Docker 来运行大模型。Docker 是一个开放源代码的平台,允许开发者自动化应用程序的部署、扩展和管理。通过将大模型放入 Docker 容器中,我们可以确保其在各…...
热门与冷门并存,25西电—电子工程学院(考研录取情况)
1、电子工程学院各个方向 2、电子工程学院近三年复试分数线对比 学长、学姐分析 由表可看出: 1、电子科学与技术25年相较于24年上升20分 2、信息与通信工程、控制科学与工程、新一代电子信息技术(专硕)25年相较于24年下降25分 3、25vs24推…...
Warcraft Logs [Classic] [WCL] BOSS ID query
Warcraft Logs [Classic] [WCL] BOSS ID query 所有副本BOSSID查询 https://wowpedia.fandom.com/wiki/DungeonEncounterID#Retail IDNameMapInstanceIDPatch227High Interrogator GerstahnBlackrock Depths230228Lord RoccorBlackrock Depths230229Houndmaster GrebmarBlackro…...
python录屏工具实现
python录屏工具实现 实现一 按Ctrl+Shift+8开始录制,按Ctrl+Shift+9结束录制,视频保存到“ d:\录屏视频”目录中。 先看用了哪些库 import cv2: 引入 OpenCV 库,这是一个开源计算机视觉库,用于图像和视频处理。在这个程序中,它用于创建视频文件、处理图像等。需要安装ope…...
架构师面试(三十一):IM 消息收发逻辑
问题 今天聊一下 IM 系统最核心的业务逻辑。 在上一篇短文《架构师面试(三十):IM 分层架构》中详细分析过,IM 水平分层架构包括:【入口网关层】、【业务逻辑层】、【路由层】和【数据访问层】;除此之外&a…...
基于若依框架前后端分离的项目部署
文章目录 单项目的部署项目目录后端打包上传前端打包上传配置nginx服务器打开防火墙完成 两个项目的部署两个项目介绍后端打包并上传前端打包并上传nginx配置服务器端口开放完成 腾讯云服务器 之 环境搭建 单项目的部署 项目目录 后端打包上传 查看端口号 在ruoyi-admin的appl…...
黑马Java基础笔记-1
JVM,JDK和JRE JDK是java的开发环境 JVM虚拟机:Java程序运行的地方 核心类库:Java已经写好的东西,我们可以直接用。 System.out.print中的这些方法就是核心库中的所包含的 开发工具: javac(编译工具)、java&…...
面向新一代扩展现实(XR)应用的物联网框架
中文标题: 面向新一代扩展现实(XR)应用的物联网框架 英文标题: Towards an IoT Framework for the New Generation of XR Applications 作者信息 Joo A. Dias,UNIDCOM - IADE,欧洲大学,里斯本&…...
pcl各模块
参考资料: https://github.com/Ewenwan/MVision/blob/master/PCL_APP/1_%E7%82%B9%E4%BA%91%E6%BB%A4%E6%B3%A2filter.md 点云库PCL各模块学习 语雀 各模块依赖关系: 模块: common pcl_common中主要是包含了PCL库常用的公共数据结构和方…...
Oracle Recovery Tools修复ORA-600 6101/kdxlin:psno out of range故障
数据库异常断电,然后启动异常,我接手该库,尝试recover恢复 SQL> recover database; ORA-10562: Error occurred while applying redo to data block (file# 2, block# 63710) ORA-10564: tablespace SYSAUX ORA-01110: ???????? 2: H:\TEMP\GDLISNET\SYSAUX01.DBF O…...
Python网络编程从入门到精通:Socket核心技术+TCP/UDP实战详解
引言 网络编程是构建现代分布式系统的核心能力,而Socket作为通信的基石,其重要性不言而喻。本文将从零开始,通过清晰的代码示例、原理剖析和对比分析,带你彻底掌握Python中的Socket编程技术,涵盖TCP可靠连接、UDP高效…...
2025MathorcupC题 音频文件的高质量读写与去噪优化 保姆级教程讲解|模型讲解
2025Mathorcup数学建模挑战赛(妈妈杯)C题保姆级分析完整思路代码数据教学 C题:音频文件的高质量读写与去噪优化 随着数字媒体技术的迅速发展,音频处理成为信息时代的关键技术之一。在日常生活中,从录音设备捕捉的原始…...
.net core web api 数据验证(DataAnnotations)
目录 一、什么是 DataAnnotations? 二、扩展验证逻辑(自定义验证器) 一、什么是 DataAnnotations? DataAnnotations 是一组特性(Attributes),用于在模型类上定义验证规则。主要用于属性级别的…...
【工具-Krillin AI】视频翻译、配音、语音克隆于一体的一站式视频多语言转换工具~
Krillin AI 是全能型音视频本地化与增强解决工具。这款简约而强大的工具,集音视频翻译、配音、语音克隆于一身,支持横竖屏格式输出,确保在所有主流平台(哔哩哔哩,小红书,抖音,视频号,…...
ICPR-2025 | 让机器人在未知环境中 “听懂” 指令精准导航!VLTNet:基于视觉语言推理的零样本目标导航
作者:Congcong Wen, Yisiyuan Huang, Hao Huang ,Yanjia Huang, Shuaihang Yuan, YuHao, HuiLin and Yi Fang 单位:纽约大学阿布扎比分校具身人工智能与机器人实验室,纽约大学阿布扎比分校人工智能与机器人中心,纽约大学坦登工程…...
