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

hdfs源码解析之DFSClient

1、DFSClient类简介

    DFSClient 是 Hadoop 分布式文件系统(HDFS)中的一个核心类,用于客户端与 HDFS 之间的交互。它提供了一组方法,使客户端应用程序可以方便地与 HDFS 进行通信,包括文件的读取、写入、创建、删除、重命名等操作。DFSClient 封装了与 NameNode 和 DataNode 的通信细节,使得客户端开发者可以通过高级 API 进行文件系统操作,而不必关心底层的实现细节。

2、DFSClient主要功能

2.1、文件读取和写入

  • 提供方法用于读取和写入 HDFS 上的文件。
  • 例如,open 方法用于打开文件以读取,create 方法用于创建新文件以写入。

2.2、文件操作

  • 支持文件的创建、删除、重命名、追加等操作。
  • 例如,delete 方法用于删除文件或目录,rename 方法用于重命名文件或目录。

2.3、目录操作

  • 支持创建、删除和列出目录。
  • 例如,mkdirs 方法用于创建目录,listPaths 方法用于列出目录内容。

2.4、获取文件和目录信息

  • 提供方法获取文件和目录的元数据信息。
  • 例如,getFileInfo 方法用于获取文件或目录的详细信息,getLocatedBlocks 方法用于获取文件的块位置。

2.5、与NN、DN通信

  • 管理与 NameNode 的通信,用于获取文件的元数据和块位置信息。
  • 管理与 DataNode 的通信,用于读取和写入实际的数据块。

3、DFSClient核心源码

    DFSClient源码主要包括:创建客户端连接(配置获取、令牌处理、连接地址解析)

3.1、构造方法

3.1.1、代码概述

该构造函数已废弃,接受一个Configuration对象,并调用另一个构造函数获取NameNode地址

  @Deprecatedpublic DFSClient(Configuration conf) throws IOException {this(DFSUtilClient.getNNAddress(conf), conf);}

该构造函数接受一个InetSocketAddress对象和一个Configuration对象,并将InetSocketAddress 转换为URI然后调用另一个基于URI的构造函数

  public DFSClient(InetSocketAddress address, Configuration conf)throws IOException {this(DFSUtilClient.getNNUri(address), conf);}

该构造函数接受一个URI对象和一个Configuration对象,并将FileSystem.Statistics参数设置为 null,然后调用另一个更完整的构造函数

  public DFSClient(URI nameNodeUri, Configuration conf) throws IOException {this(nameNodeUri, conf, null);}

该构造函数接受一个URI对象、一个Configuration对象和一个FileSystem.Statistics对象,然后调用最完整的构造函数

  public DFSClient(URI nameNodeUri, Configuration conf,FileSystem.Statistics stats) throws IOException {this(nameNodeUri, null, conf, stats);}

 最底层构造函数,该方法不建议直接调用。

  @VisibleForTestingpublic DFSClient(URI nameNodeUri, ClientProtocol rpcNamenode,Configuration conf, FileSystem.Statistics stats) throws IOException {// Copy only the required DFSClient configurationthis.tracer = FsTracer.get(conf);this.dfsClientConf = new DfsClientConf(conf);this.conf = conf;this.stats = stats;this.socketFactory = NetUtils.getSocketFactory(conf, ClientProtocol.class);this.dtpReplaceDatanodeOnFailure = ReplaceDatanodeOnFailure.get(conf);this.dtpReplaceDatanodeOnFailureReplication = (short) conf.getInt(HdfsClientConfigKeys.BlockWrite.ReplaceDatanodeOnFailure.MIN_REPLICATION,HdfsClientConfigKeys.BlockWrite.ReplaceDatanodeOnFailure.MIN_REPLICATION_DEFAULT);LOG.debug("Sets {} to {}",HdfsClientConfigKeys.BlockWrite.ReplaceDatanodeOnFailure.MIN_REPLICATION, dtpReplaceDatanodeOnFailureReplication);this.ugi = UserGroupInformation.getCurrentUser();this.namenodeUri = nameNodeUri;this.clientName = "DFSClient_" + dfsClientConf.getTaskId() + "_" +ThreadLocalRandom.current().nextInt()  + "_" +Thread.currentThread().getId();int numResponseToDrop = conf.getInt(DFS_CLIENT_TEST_DROP_NAMENODE_RESPONSE_NUM_KEY,DFS_CLIENT_TEST_DROP_NAMENODE_RESPONSE_NUM_DEFAULT);ProxyAndInfo<ClientProtocol> proxyInfo = null;AtomicBoolean nnFallbackToSimpleAuth = new AtomicBoolean(false);if (numResponseToDrop > 0) {// This case is used for testing.LOG.warn("{} is set to {} , this hacked client will proactively drop responses",DFS_CLIENT_TEST_DROP_NAMENODE_RESPONSE_NUM_KEY, numResponseToDrop);proxyInfo = NameNodeProxiesClient.createProxyWithLossyRetryHandler(conf,nameNodeUri, ClientProtocol.class, numResponseToDrop,nnFallbackToSimpleAuth);}if (proxyInfo != null) {this.dtService = proxyInfo.getDelegationTokenService();this.namenode = proxyInfo.getProxy();} else if (rpcNamenode != null) {// This case is used for testing.Preconditions.checkArgument(nameNodeUri == null);this.namenode = rpcNamenode;dtService = null;} else {Preconditions.checkArgument(nameNodeUri != null,"null URI");proxyInfo = NameNodeProxiesClient.createProxyWithClientProtocol(conf,nameNodeUri, nnFallbackToSimpleAuth);this.dtService = proxyInfo.getDelegationTokenService();this.namenode = proxyInfo.getProxy();}String localInterfaces[] =conf.getTrimmedStrings(DFS_CLIENT_LOCAL_INTERFACES);localInterfaceAddrs = getLocalInterfaceAddrs(localInterfaces);if (LOG.isDebugEnabled() && 0 != localInterfaces.length) {LOG.debug("Using local interfaces [{}] with addresses [{}]",Joiner.on(',').join(localInterfaces),Joiner.on(',').join(localInterfaceAddrs));}Boolean readDropBehind =(conf.get(DFS_CLIENT_CACHE_DROP_BEHIND_READS) == null) ?null : conf.getBoolean(DFS_CLIENT_CACHE_DROP_BEHIND_READS, false);Long readahead = (conf.get(DFS_CLIENT_CACHE_READAHEAD) == null) ?null : conf.getLongBytes(DFS_CLIENT_CACHE_READAHEAD, 0);this.serverDefaultsValidityPeriod = conf.getTimeDuration(DFS_CLIENT_SERVER_DEFAULTS_VALIDITY_PERIOD_MS_KEY,DFS_CLIENT_SERVER_DEFAULTS_VALIDITY_PERIOD_MS_DEFAULT,TimeUnit.MILLISECONDS);Boolean writeDropBehind =(conf.get(DFS_CLIENT_CACHE_DROP_BEHIND_WRITES) == null) ?null : conf.getBoolean(DFS_CLIENT_CACHE_DROP_BEHIND_WRITES, false);this.defaultReadCachingStrategy =new CachingStrategy(readDropBehind, readahead);this.defaultWriteCachingStrategy =new CachingStrategy(writeDropBehind, readahead);this.clientContext = ClientContext.get(conf.get(DFS_CLIENT_CONTEXT, DFS_CLIENT_CONTEXT_DEFAULT),dfsClientConf, conf);if (dfsClientConf.getHedgedReadThreadpoolSize() > 0) {this.initThreadsNumForHedgedReads(dfsClientConf.getHedgedReadThreadpoolSize());}this.initThreadsNumForStripedReads(dfsClientConf.getStripedReadThreadpoolSize());this.saslClient = new SaslDataTransferClient(conf, DataTransferSaslUtil.getSaslPropertiesResolver(conf),TrustedChannelResolver.getInstance(conf), nnFallbackToSimpleAuth);}

3.1.2、重点剖析

DFSClient的核心构建方式是传入namenode节点对应的URI以及配置信息,也是我们构建DFSClient通常使用的方法

public DFSClient(URI nameNodeUri, Configuration conf) throws IOException {this(nameNodeUri, conf, null);
}

3.2、委托令牌处理      

        这段源码是一个用于续约和取消 HDFS 委托令牌(Delegation Token)的 Renewer 类,它继承自 TokenRenewer 类。主要功能是通过与 NameNode 通信,维护和管理委托令牌的生命周期。

3.2.1、代码概述

3.2.2、重点剖析

  • static静态代码块为初始化hdfs配置文件;
  • handleKind方法用于判断是否处理指定类型的委托令牌,在当前源码中会默认判定是否为HDFS的委托令牌类型;
  • renew 方法用于续约委托令牌。它通过 getNNProxy 方法获取到与委托令牌对应的 NameNode 代理,然后调用 renewDelegationToken 方法进行委托令牌的续约操作;
  • cancel 方法用于取消委托令牌。它也通过 getNNProxy 方法获取 NameNode 代理,然后调用 cancelDelegationToken 方法执行委托令牌的取消操作;
  • getNNProxy 方法根据委托令牌获取对应的 NameNode 代理。它首先根据委托令牌的信息构建 URI,然后通过 NameNodeProxiesClient 类的静态方法创建 NameNode 的代理对象,并返回该代理对象。

3.3、getLocalInterfaceAddrs

3.3.1、代码概述

       这个方法的作用是接受一个接口名称的数组,并根据每个接口名称解析成对应的本地地址(可以是 IP 地址、子网或域名)。它首先尝试将接口名称视为一个 IP 地址,如果不是,则检查它是否是一个有效的子网,如果仍然不是,则假定它是一个域名,并通过 DNS 解析。最终,所有解析出的地址都被封装为 InetSocketAddress 对象,并返回一个包含这些地址的数组。

private static SocketAddress[] getLocalInterfaceAddrs(String interfaceNames[]) throws UnknownHostException {List<SocketAddress> localAddrs = new ArrayList<>();for (String interfaceName : interfaceNames) {if (InetAddresses.isInetAddress(interfaceName)) {localAddrs.add(new InetSocketAddress(interfaceName, 0));} else if (NetUtils.isValidSubnet(interfaceName)) {for (InetAddress addr : NetUtils.getIPs(interfaceName, false)) {localAddrs.add(new InetSocketAddress(addr, 0));}} else {for (String ip : DNS.getIPs(interfaceName, false)) {localAddrs.add(new InetSocketAddress(ip, 0));}}}return localAddrs.toArray(new SocketAddress[localAddrs.size()]);}

3.3.2、重点剖析

  1. 该方法首先检查interfaceName是否是一个有效的IP地址:
  2. 如果不是IP地址,检查interfaceName是否是一个有效的子网:
  3. 如果是有效的子网,获取该子网中的所有IP地址,并将每个IP地址封装为InetSocketAddress对象,添加到localAddrs列表中。
  4. 如果既不是IP地址也不是子网,假定它是一个域名:
  5. 通过DNS解析获取该域名的所有IP地址,并将每个IP地址封装为InetSocketAddress对象,添加到localAddrs列表中。

3.4、getRandomLocalInterfaceAddr

3.4.1、代码概述

        这个方法的作用是从一组预先配置的本地接口地址 (localInterfaceAddrs 数组) 中随机选择一个地址并返回。

SocketAddress getRandomLocalInterfaceAddr() {if (localInterfaceAddrs.length == 0) {return null;}final int idx = r.nextInt(localInterfaceAddrs.length);final SocketAddress addr = localInterfaceAddrs[idx];LOG.debug("Using local interface {}", addr);return addr;}

3.4.2、重点剖析

  1. 检查 localInterfaceAddrs 数组是否为空,如果为空则返回 null
  2. 使用随机数生成器 r 生成一个随机索引 idx
  3. 获取并返回 localInterfaceAddrs 数组中对应索引 idxSocketAddress 对象。
  4. 在返回之前,记录调试日志以便于跟踪选中的本地接口地址。

3.5、读写超时时间判定

3.5.1、代码概述

        这段代码包含两个方法:getDatanodeWriteTimeoutgetDatanodeReadTimeout,它们用于计算数据节点写入和读取的超时时间。每个方法都接收一个参数 numNodes,表示数据节点的数量。

int getDatanodeWriteTimeout(int numNodes) {final int t = dfsClientConf.getDatanodeSocketWriteTimeout();return t > 0? t + HdfsConstants.WRITE_TIMEOUT_EXTENSION*numNodes: 0;
}int getDatanodeReadTimeout(int numNodes) {final int t = dfsClientConf.getSocketTimeout();return t > 0? HdfsConstants.READ_TIMEOUT_EXTENSION*numNodes + t: 0;
}

3.5.2、重点剖析

  1. 通过dfsclientconf获取写入\读取超时时间t;
  2. 如果t大于0则返回 t 加上一个扩展超时时间,这个扩展超时时间是常量 HdfsConstants.WRITE_TIMEOUT_EXTENSION 乘以 numNodes(数据节点数量)
  3. 如果t<=0,则返回0

3.6、租约管理

3.6.1、代码概述

        这段代码定义了三个方法:getLeaseRenewerbeginFileLeaseendFileLease,用于管理HDFS中的文件租约。文件租约机制确保文件在写入过程中不会被其他客户端修改或删除。

public LeaseRenewer getLeaseRenewer() {return LeaseRenewer.getInstance(namenodeUri != null ? namenodeUri.getAuthority() : "null", ugi, this);}/** Get a lease and start automatic renewal */private void beginFileLease(final String key, final DFSOutputStream out) {synchronized (filesBeingWritten) {putFileBeingWritten(key, out);LeaseRenewer renewer = getLeaseRenewer();boolean result = renewer.put(this);if (!result) {// Existing LeaseRenewer cannot add another Daemon, so remove existing// and add new one.LeaseRenewer.remove(renewer);renewer = getLeaseRenewer();renewer.put(this);}}}/** Stop renewal of lease for the file. */void endFileLease(final String renewLeaseKey) {synchronized (filesBeingWritten) {removeFileBeingWritten(renewLeaseKey);// remove client from renewer if no files are openif (filesBeingWritten.isEmpty()) {getLeaseRenewer().closeClient(this);}}}

3.6.2、重点剖析

  • 获取租约续约器getLeaseRenewer 方法返回一个 LeaseRenewer 实例,用于管理租约的续约。        
    • 获取租约续约器
    • 调用 LeaseRenewer.getInstance 方法获取 LeaseRenewer 实例。
    • 如果 namenodeUri 不为空,则使用其权限部分(authority),否则使用 "null"。ugi(用户组信息)和当前 DFSClient 实例(this)作为参数传递给 LeaseRenewer.getInstance
  • 开始文件租约beginFileLease 方法将文件添加到写入记录中,并确保当前客户端的租约续约器能够处理该文件的续约。
    • 使用 key 和 out(DFSOutputStream 实例)调用 putFileBeingWritten 方法,记录正在写入的文件;
    • 获取 LeaseRenewer 实例;
    • 调用 renewer.put(this) 方法将当前客户端添加到租约续约器中;
    • 如果返回结果为 false(表示现有的 LeaseRenewer 不能添加新的守护线程),则移除现有的 LeaseRenewer,获取新的 LeaseRenewer 实例,并将当前客户端添加到新的 LeaseRenewer 中;
  • 结束文件租约endFileLease 方法移除文件写入记录,并在没有文件写入时关闭客户端的租约续约
    • 使用 renewLeaseKey 调用 removeFileBeingWritten 方法,从记录中移除正在写入的文件
    • 如果没有文件在写入(filesBeingWritten 为空),则获取 LeaseRenewer 实例,调用 renewer.closeClient(this) 方法,关闭当前客户端的租约续约。

todo,未完待续

相关文章:

hdfs源码解析之DFSClient

1、DFSClient类简介 DFSClient 是 Hadoop 分布式文件系统&#xff08;HDFS&#xff09;中的一个核心类&#xff0c;用于客户端与 HDFS 之间的交互。它提供了一组方法&#xff0c;使客户端应用程序可以方便地与 HDFS 进行通信&#xff0c;包括文件的读取、写入、创建、删除、重命…...

智能化立体仓库的种类有哪些?

在仓储运输系统中&#xff0c;自动化立体仓库可充分利用空间储存货物&#xff0c;故而也被称之为高层货架仓库。在实际应用中&#xff0c;自动化仓库系统是不需人工处理的情况下能自动存储和取出物料的系统。那么&#xff0c;智能化立体仓库的种类有哪些&#xff1f;下面就让小…...

Stable Diffusion 3 如何下载安装使用及性能优化

Stable Diffusion 3 Stable Diffusion 3&#xff08;SD3&#xff09;&#xff0c;Stability AI最新推出的Stable Diffusion模型系列&#xff0c;现在可以在Hugging Face Hub上使用&#xff0c;并且可以与Diffusers一起使用。 今天发布的模型是Stable Diffusion 3 Medium&…...

c语言操作符详解

操作符详解 正数的原码反码补码相同 负数的原码最高位数是1&#xff0c;正数为0 整数在内存中存储的是补码 负数的左移与右移&#xff0c;移的是补码&#xff0c;打印的是源码 补码-1取反就是原码。 左移有乘2的效果 左移和右移只针对整数。 vs里的右移操作赋采用的是算数右…...

【耐水好】强耐水UV胶水它的粘接强度和普通UV胶水比如何呢

【耐水好】强耐水UV胶水它的粘接强度和普通UV胶水比如何呢 强耐水UV胶水的粘接强度与普通UV胶水相比&#xff0c;具有显著的优势。以下是详细的比较和归纳&#xff1a; 固化方式&#xff1a; 两者都是通过紫外线&#xff08;UV&#xff09;照射进行固化&#xff0c;但强耐水UV…...

jumpserver堡垒机集群搭建

1、环境 操作系统&#xff1a;龙蜥os 7.9 firewall-cmd --permanent --zonepublic --remove-servicessh firewall-cmd --permanent --zonepublic --add-rich-rulerule familyipv4 source address10.90.101.1 port port22 protocoltcp accept firewall-cmd --reload2、安装NFS…...

Termius for Mac/Win:跨平台多协议远程管理利器

Termius for Mac/Win是一款备受瞩目的跨平台多协议远程管理软件&#xff0c;以其卓越的性能、丰富的功能和便捷的操作体验&#xff0c;赢得了广大用户的青睐。无论是在企业IT管理、系统维护&#xff0c;还是个人远程连接、文件传输等方面&#xff0c;Termius都展现出了出色的实…...

Unity OpenCVForUnity 安装和第二个案例详解 <二>

目录 一、前言 二、场景介绍 1.WebCamTextureToMatExample脚本 2.FpsMonitor脚本 三、 结构体Scaler 四、找到相机并使用 1.相机的启用 2.格式转换 a.把webCamTexture转换成Mat b.把Mat转换成Texture2D 五、脚本组合 六、作者的碎碎念 一、前言 第二个案例&#xf…...

Lua实现自定义函数面向对象编程

本文目录 1、引言2、原理3、实例4、层析验证 文章对应视频教程&#xff1a; 暂无&#xff0c;可以关注我的B站账号等待更新。 点击图片或链接访问我的B站主页~~~ 1、引言 在现代软件开发中&#xff0c;面向对象编程&#xff08;OOP&#xff09;已经成为一种广泛使用的编程范式…...

docker安装消息队列mq中的rabbit服务

在现代化的分布式系统中&#xff0c;消息队列&#xff08;Message Queue, MQ&#xff09;已经成为了一种不可或缺的组件。RabbitMQ作为一款高性能、开源的消息队列软件&#xff0c;因其高可用性、可扩展性和易用性而广受欢迎。本文将详细介绍如何在Docker环境中安装RabbitMQ服务…...

OpenAI新模型发布,免费开放GPT-4o!但只开放一点点...

GPT-4o 中的“o”代表“omni”——指的是 GPT-4o 的多模态。 该模型将向免费客户开放&#xff0c;这意味着任何人都可以通过 ChatGPT 访问 OpenAI 最先进的技术。 GPT-4o 是 OpenAI 昨天晚上发布的新旗舰模型&#xff0c;可以实时推理音频、视觉和文本。 据官方介绍&#xff0…...

idea的右边栏maven不见了(丢了)解决方案以及idea无法识别maven项目

前言 众所周知&#xff0c;idea是java开发中不可缺少的利器&#xff0c;但是由于功能过多&#xff0c;导致奇怪的问题也很多 问题汇总 idea的右边栏maven丢了 idea无法识别maven项目 对应的解决办法 idea的右边栏maven丢了 原因可能是被自己手动移除了 或者 项目没被正确…...

等待 chrome.storage.local.get() 完成

chrome.storage.local.get() 获取存储处理并计数&#xff0c;内部计数正常&#xff0c;外部使用始终为0&#xff0c;百思不得其解。 如何在继续执行之前等待异步chrome.storage.local.get()完成-腾讯云开发者社区-腾讯云 (tencent.com) 原来我忽略了异步问题&#xff0c;最简…...

004 AOP使用

文章目录 基于AspectJ的AOP的使用添加依赖编写目标类和目标方法使用XML实现实现步骤切入点表达式通知类型 使用注解实现实现步骤环绕通知注解配置定义通用切入点 纯注解方式 基于AspectJ的AOP的使用 其实就是指的SpringAspectJ整合&#xff0c;不过Spring已经将AspectJ收录到自…...

Zookeeper 集群广播事务性能如何保证?

Zookeeper 集群广播事务性能如何保证? zookeeper是如何保证广播事务时,从开始到多数节点确认事务这个高效的? 在 Zookeeper 中,确保广播事务从开始到多数节点确认的高效性至关重要。Zookeeper 通过以下几个关键机制 和优化策略来实现这一目标: ZAB 协议(Zookeeper Atom…...

【vue解决el-input组件自动填充用户名密码】

解决el-input组件自动填充用户名密码 发现用autocomplete"off"并不能解决el-input组件自动填充密码的问题。 解决方法 auto-complete"new-password" 在el-input组件添加auto-complete"new-password" 即可...

案例练习:演讲比赛

演讲比赛: 比赛规则&#xff1a; 某市举行一场演讲比赛&#xff08; speech_contest &#xff09;&#xff0c;共有 24 个人参加。比赛共三轮&#xff0c;前两轮为淘汰赛&#xff0c;第三轮为决赛。 比赛方式&#xff1a;分组比赛&#xff0c;每组 6 个人&#xff1b;选手每次…...

推荐一个很好用的Latex写代码的软件

软件名称&#xff1a;Axmath 据说是国产软件&#xff0c;好用是真好用&#xff08;去哪找&#xff1f;比如某地球号的公主号或其他地方&#xff09;我是推荐付费购买使用 1.通过图形操作&#xff0c;选择要转成Latex代码的符号&#xff0c;按下转换&#xff0c;直接就出现了我…...

windows 程序右键管理员点击无响应

Windows 程序在右键单击以管理员身份运行时没有响应&#xff0c;可能是由于多种原因引起的。下面是一些常见的问题和解决方案&#xff1a; 1. 用户账户控制 (UAC) 设置问题&#xff1a; - 试着降低或提高 UAC 设置&#xff0c;然后再试一次。可以在控制面板的“用户账户”部…...

开发基于Java语言的SaaS(Software-as-a-Service,软件即服务)模式的HIS系统详解 HIS系统源码 支持二开

开发基于Java语言的SaaS&#xff08;Software-as-a-Service&#xff0c;软件即服务&#xff09;模式的HIS系统详解 HIS系统源码 支持二开 开发基于Java语言的SaaS&#xff08;Software-as-a-Service&#xff0c;软件即服务&#xff09;模式的HIS&#xff08;Hospital Informat…...

无法与IP建立连接,未能下载VSCode服务器

如题&#xff0c;在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈&#xff0c;发现是VSCode版本自动更新惹的祸&#xff01;&#xff01;&#xff01; 在VSCode的帮助->关于这里发现前几天VSCode自动更新了&#xff0c;我的版本号变成了1.100.3 才导致了远程连接出…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍&#xff1a; img 属性指定分区存放的 image 名称&#xff0c;指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件&#xff0c;则以 proj_name:binary_name 格式指定文件名&#xff0c; proj_name 为工程 名&…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill

视觉语言模型&#xff08;Vision-Language Models, VLMs&#xff09;&#xff0c;为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展&#xff0c;机器人仍难以胜任复杂的长时程任务&#xff08;如家具装配&#xff09;&#xff0c;主要受限于人…...

破解路内监管盲区:免布线低位视频桩重塑停车管理新标准

城市路内停车管理常因行道树遮挡、高位设备盲区等问题&#xff0c;导致车牌识别率低、逃费率高&#xff0c;传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法&#xff0c;正成为破局关键。该设备安装于车位侧方0.5-0.7米高度&#xff0c;直接规避树枝遮…...

Leetcode33( 搜索旋转排序数组)

题目表述 整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。 在传递给函数之前&#xff0c;nums 在预先未知的某个下标 k&#xff08;0 < k < nums.length&#xff09;上进行了 旋转&#xff0c;使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...

c# 局部函数 定义、功能与示例

C# 局部函数&#xff1a;定义、功能与示例 1. 定义与功能 局部函数&#xff08;Local Function&#xff09;是嵌套在另一个方法内部的私有方法&#xff0c;仅在包含它的方法内可见。 • 作用&#xff1a;封装仅用于当前方法的逻辑&#xff0c;避免污染类作用域&#xff0c;提升…...

沙箱虚拟化技术虚拟机容器之间的关系详解

问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西&#xff0c;但是如果把三者放在一起&#xff0c;它们之间到底什么关系&#xff1f;又有什么联系呢&#xff1f;我不是很明白&#xff01;&#xff01;&#xff01; 就比如说&#xff1a; 沙箱&#…...

Canal环境搭建并实现和ES数据同步

作者&#xff1a;田超凡 日期&#xff1a;2025年6月7日 Canal安装&#xff0c;启动端口11111、8082&#xff1a; 安装canal-deployer服务端&#xff1a; https://github.com/alibaba/canal/releases/1.1.7/canal.deployer-1.1.7.tar.gz cd /opt/homebrew/etc mkdir canal…...

Qwen系列之Qwen3解读:最强开源模型的细节拆解

文章目录 1.1分钟快览2.模型架构2.1.Dense模型2.2.MoE模型 3.预训练阶段3.1.数据3.2.训练3.3.评估 4.后训练阶段S1: 长链思维冷启动S2: 推理强化学习S3: 思考模式融合S4: 通用强化学习 5.全家桶中的小模型训练评估评估数据集评估细节评估效果弱智评估和民间Arena 分析展望 如果…...

react-pdf(pdfjs-dist)如何兼容老浏览器(chrome 49)

之前都是使用react-pdf来渲染pdf文件&#xff0c;这次有个需求是要兼容xp环境&#xff0c;xp上chrome最高支持到49&#xff0c;虽然说iframe或者embed都可以实现预览pdf&#xff0c;但为了后续的定制化需求&#xff0c;还是需要使用js库来渲染。 chrome 49测试环境 能用的测试…...