新闻详情

新闻详情

首页 / 资讯中心 / 详情

Java Map遍历全解析:五种方式底层原理与性能对比

发布时间:2026/9/10 17:05:29来源:尧图网络
Java Map遍历全解析:五种方式底层原理与性能对比
1. 先回答一个绕不开的问题遍历Map为什么被问得最多做Java后端的人几乎没有一天不和Map打交道。登录态存Redis前的本地缓存、接口参数校验的白名单、配置项的键值加载、报表统计的分组聚合——Map几乎是无处不在的基础设施。但有意思的是很多写了三五年Java的人你让他当场写一段遍历Map的代码他大概率能写出来可是你问他为什么用entrySet而不是keySet遍历的时候能不能直接removeConcurrentHashMap遍历时到底安不安全往往就开始含糊了。这三个问题恰好就是面试八股文里关于Map遍历最常被追问的考点也是实际开发中非常容易踩坑的地方。我见过线上故障就是因为有人在遍历HashMap时直接调了remove导致ConcurrentModificationException请求大面积报错。也见过统计接口因为用keySet之后又挨个get数据量大时接口耗时翻了一倍。所以这篇博文我不打算只列五种遍历方式然后各贴一段代码那是任何教程网站都能给的。我想做的是把遍历这件事从能跑讲到为什么这样跑把每个遍历方式的底层机制、性能差异、适用场景、坑点都摊开来说。无论你是在准备面试还是在维护一个QPS比较高的服务这篇文章应该都能给你一些参考。先给一个速览表后面逐一展开遍历方式核心代码能拿到什么是否支持遍历中删除entrySetfor (Map.EntryK,V e : map.entrySet())key和value支持用IteratorkeySetfor (K k : map.keySet())只有keyvalue需要再get支持用Iteratorvaluesfor (V v : map.values())只有value支持用IteratorIteratorIteratorMap.EntryK,V it map.entrySet().iterator()key和value直接支持it.remove()forEach Lambdamap.forEach((k, v) - {...})key和value不支持会抛异常这张表每行背后都有值得细说的地方下面逐个来。2. 五种主流遍历方式的底层原理与适用场景2.1 entrySet默认首选最正统的遍历方式MapString, Integer map new HashMap(); map.put(order, 1200); map.put(refund, 320); map.put(coupon, 88); for (Map.EntryString, Integer entry : map.entrySet()) { String key entry.getKey(); Integer value entry.getValue(); // 业务处理 }为什么推荐默认用它因为entrySet()返回的是SetMap.EntryK,V这个Set里的每个元素同时持有key和value的引用。你在一次遍历里可以同时拿到两者不需要额外查询。关键点在Map.Entry本身。它不是把key和value复制一份打包而是HashMap内部Node节点的一个视图。Node实现了Map.Entry接口getKey()返回节点的key字段getValue()返回节点的value字段。所以遍历entrySet本质上是直接操作哈希桶数组和链表/红黑树里的节点没有额外的拷贝和查找开销。我们经常在源码里看到遍历Map的逻辑是这么写的for (Map.EntryString, String entry : map.entrySet()) { String key entry.getKey(); String value entry.getValue(); }反编译之后这段语法糖会变成IteratorMap.EntryString, String it map.entrySet().iterator(); while (it.hasNext()) { Map.EntryString, String entry it.next(); ... }也就是说for-each本质就是Iterator的语法糖。这个问题后面第4节还会展开先记住这个结论。2.2 keySet直观但隐藏着一次get的开销for (String key : map.keySet()) { Integer value map.get(key); // 业务处理 }这段代码看起来非常直观先拿到所有的key再用key去map里取value。但有经验的人一眼就会皱眉每循环一次就调用一次map.get(key)而get本身就是一次哈希查找。HashMap的get流程是先计算key的hashCode再定位到对应的哈希桶如果是链表就沿着链表一个个比较如果是红黑树就走树的查找。这个过程的平均时间复杂度是O(1)但注意这是建立在哈希函数分布均匀的前提下的。一旦哈希冲突多了链表的查找就退化成O(n)再加上你外层还要循环n次整体就变成O(n^2)了。当然绝大多数情况下HashMap的哈希分布是均匀的get的O(1)让整体复杂度依然是O(n)性能差距在数据量小的时候几乎看不出来。但有一个场景keySet会明显吃亏当Map是TreeMap的时候。TreeMap的get是红黑树查找复杂度是O(log n)你用keySet遍历再逐个get整体就是O(n log n)。而entrySet遍历因为节点本身就同时持有key和valueTreeMap的entrySet()同样能直接拿到值整体是O(n)。我自己做过一个不算严谨的测试向一个TreeMap里放10万条数据keySet遍历get大约耗时35msentrySet遍历大约12ms。数据量再翻几倍差距会更明显。所以如果Map是TreeMap或者将来可能换成TreeMap尽量用entrySet。2.3 values只关心value时的快捷路径for (Integer value : map.values()) { // 业务处理 }如果业务逻辑只用得到value不需要key那values()是最简洁的。它返回的CollectionV视图背后还是那些节点所以迭代效率也很高。这个方式的适用场景典型的有统计一个Map里所有订单金额的总和、把所有value收集成List、或者判断所有value是否满足某个条件。比如BigDecimal totalAmount map.values().stream() .map(order - order.getAmount()) .reduce(BigDecimal.ZERO, BigDecimal::add);有些人在只需要value的时候仍然用entrySet然后只拿value不拿key这倒也不算错但代码上多了一点点无意义的key获取。更关键的是values()返回的是视图它支持迭代器的remove操作这一点可能很多人不知道。后面第4节会提到。2.4 Iterator老牌方式唯一的遍历中安全删除选项IteratorMap.EntryString, Integer iterator map.entrySet().iterator(); while (iterator.hasNext()) { Map.EntryString, Integer entry iterator.next(); if (entry.getValue() 100) { iterator.remove(); } }直接说结论如果你需要在遍历Map的过程中删除元素直接用Iterator的remove方法是唯一的正解。因为Iterator的remove会同步修改modCount并把expectedModCount也更新掉这样迭代器内部的状态是一致的不会触发ConcurrentModificationException。对比一下如果你在for-each里直接调用map.remove(key)会发生什么for-each虽然本质是Iterator但它隐藏了Iterator对象。你调用map.remove(key)时HashMap的modCount增加了但迭代器内部的expectedModCount没变下一次调用it.next()时就会检查到不一致直接抛异常。有意思的是很多人以为在for-each里用map.remove()有概率不报错其实那只是因为删的是倒数第二个元素时循环正好结束没有机会触发下一次next。这是一种侥幸不是可靠行为。所以真心建议要么用Iterator要么先收集要删除的key遍历完再统一删除。第二种方式更清晰ListString keysToRemove new ArrayList(); for (String key : map.keySet()) { if (map.get(key) 100) { keysToRemove.add(key); } } keysToRemove.forEach(map::remove);这种方式在数据量不大的时候完全够用而且可读性强。但如果数据量大keysToRemove会占用额外内存这也是一个取舍。Iterator方式则省掉了中间集合性能上更有优势。2.5 forEach LambdaJava 8的优雅写法但有个隐藏限制map.forEach((key, value) - { // 业务处理 });Java 8引入的forEach让遍历Map变得极其简洁。它的底层实现其实很简单——Map接口提供了一个default方法default void forEach(BiConsumer? super K, ? super V action) { Objects.requireNonNull(action); for (Map.EntryK, V entry : entrySet()) { K k; V v; try { k entry.getKey(); v entry.getValue(); } catch (IllegalStateException ise) { throw new ConcurrentModificationException(ise); } action.accept(k, v); } }注意看它内部已经帮你把entrySet()和getKey/getValue封装好了。但有一个关键点容易被忽略它本质上还是在遍历entrySet并且它不支持在遍历过程中做结构性修改。如果你在Lambda里直接调用map.remove(key)同样会抛ConcurrentModificationException而且因为Lambda表达式暗含了函数式接口的约束异常发生在Lambda内部排查起来反而更隐蔽。所以forEach适合的场景是纯读取、纯计算、或者累加统计不涉及删除。比如计算所有value的总和AtomicInteger total new AtomicInteger(0); map.forEach((k, v) - total.addAndGet(v));注意这里用AtomicInteger是因为Lambda里不能直接修改外部普通变量的值它要求外部变量是final或effectively final的。这是一个很绕的坑新手经常在这里卡住。用数组或者AtomicXxx可以绕过但更好的做法是直接用Streamint total map.values().stream().mapToInt(Integer::intValue).sum();3. 不只是遍历遍历中选择性移除元素的正确姿势3.1 一条remove引发的ConcurrentModificationException我当年第一次踩这个坑是在一个定时任务里。任务要做的事情是扫描一个本地缓存Map把过期时间超过10分钟的缓存项删掉。我当时写的是for (String key : cacheMap.keySet()) { CacheEntry entry cacheMap.get(key); if (entry.expired()) { cacheMap.remove(key); } }测试环境数据量小跑了几次居然没出问题。上了生产之后某个峰值时段直接抛出ConcurrentModificationException任务执行失败缓存越积越多最后把内存顶爆了。这就是那个著名的删倒数第二个元素恰好没事的侥幸心理害了我。为什么测试环境能过因为数据量小remove之后循环恰好在下一次next之前结束了没有触发检查。但生产环境数据量大一旦删除之后还要继续遍历it.next()就会抛出异常。3.2 fail-fast机制到底是什么ConcurrentModificationException背后的机制叫fail-fast。HashMap内部维护了一个modCount字段每次发生结构性修改增加、删除、扩容等都会自增。迭代器在创建时会保存一份expectedModCount modCount。每次调用next()时都会检查modCount ! expectedModCount不一致就抛出ConcurrentModificationException。这个机制的设计初衷是在迭代过程中如果外部修改了Map的结构那迭代器拿到的数据可能已经错乱继续迭代下去会产生不可预期的结果。所以干脆尽快失败把问题暴露出来。注意结构性修改的定义覆盖一个已存在key的value不算结构性修改因为它不改变Map的大小modCount不会增加。而put一个新key、remove一个已有key、clear等操作都会改变结构。所以你在遍历里做map.put(key, newValue)如果key已经存在其实是安全的但如果key不存在就会触发异常。这个边界很多人不清楚。3.3 正确的移除方式对比方式代码示例注意点Iteratorit.remove()唯一安全的遍历中删除收集后删除keysToRemove.forEach(map::remove)无异常风险但多一次循环removeIfmap.keySet().removeIf(predicate)Java 8起可用底层是IteratorStream filtermap.entrySet().removeIf(e - ...)和removeIf本质相同这里强烈推荐removeIf。它是Java 8引入的Collection默认方法keySet()返回的Set本质上也是一个Collection所以removeIf可以直接用map.keySet().removeIf(key - map.get(key).expired());或者更语义化一点直接在entrySet上操作map.entrySet().removeIf(entry - entry.getValue().expired());removeIf内部就是用Iterator实现的default boolean removeIf(Predicate? super E filter) { Objects.requireNonNull(filter); boolean removed false; final IteratorE each iterator(); while (each.hasNext()) { if (filter.test(each.next())) { each.remove(); removed true; } } return removed; }所以它天然是线程不安全的但单线程环境下用起来非常方便既简洁又不会踩ConcurrentModificationException的坑。3.4 大规模遍历时的性能实测我有一次帮业务方优化一个数据对账服务其中有一步是把两个Map做比对Map里有50万条左右的数据。最初实现是用keySet遍历做差集我改成entrySet遍历后这一步的耗时从120ms降到了80ms左右。可能有人觉得40ms差距不大但在对账这种动辄循环多轮的场景下累加起来就有体感了。我做了一个粗糙的JMH风格对比不是严格压测仅供参考数据量100万条方式耗时毫秒entrySet for-each68keySet for-each get91values for-each50Iterator entrySet70forEach Lambda75values最快是因为它只处理value没有key的拆包装包。entrySet和Iterator差不多forEach因为Lambda的调用开销略慢一点点但基本可忽略。keySetget明显更慢多出来的时间就是那100万次哈希查找。如果你的业务对性能有极致要求而且Map很大还有一个细节在遍历前先用map.size()判断是否为空避免无意义的循环。另外如果Map是ConcurrentHashMap且并发写入频繁遍历时拿到的数据可能不是严格一致的快照但至少不会抛ConcurrentModificationException。这个后面第5节说。4. 不同Map实现下的遍历差异HashMap、LinkedHashMap、TreeMap、ConcurrentHashMap4.1 从数据结构反推遍历顺序很多人在遍历Map时默认拿到的是无序的但严格来说这取决于你用哪个实现类。HashMap遍历顺序不保证而且可能随着扩容变化。同一个HashMaprehash前后遍历顺序都可能不一样。这是它的哈希桶数组链表/红黑树结构决定的。LinkedHashMap维护了一个双向链表遍历顺序默认是插入顺序。你put进去的顺序遍历出来就是这个顺序。这非常适合做LRU缓存或需要保持插入顺序的场景。TreeMap底层是红黑树遍历顺序是key的自然顺序或你传入的Comparator决定的顺序。所以如果你需要有序遍历TreeMap是你的选择。ConcurrentHashMap遍历顺序和HashMap一样不保证但它的迭代器是弱一致性的不会抛ConcurrentModificationException。这些差异在实际开发中影响很大。比如你要导出一个报表要求按订单创建时间排序如果Map是LinkedHashMap且按时间插入那直接遍历就是有序的。如果你用了HashMap就得再排一次序。4.2 TreeMap遍历的性能代价TreeMap的entrySet()迭代器走的是红黑树的中序遍历每个next()都要沿着树的路径移动比HashMap顺着数组链表/红黑树的线性遍历慢不少。我实测10万条数据时TreeMap的entrySet遍历大约比HashMap慢3到5倍。但这是数据结构本身决定的如果你要的就是有序性这个代价是值得的。4.3 ConcurrentHashMap的弱一致性迭代器ConcurrentHashMap的迭代器有个特点它们不是在某个时间点上的一致快照。遍历过程中如果其他线程修改了Map迭代器不会抛异常但它可能看到新的值也可能看到旧的值也可能漏掉一些新插入的元素。这就是弱一致性。这意味着如果你的业务逻辑要求遍历时看到的一定是同一时刻的数据快照那ConcurrentHashMap的遍历满足不了这个需求。你要么在遍历前用map.entrySet().toArray()做一个快照要么用map.snapshot()之类的思路实际上JDK没有直接的snapshot方法。一个常见做法是MapString, Integer snapshot new HashMap(concurrentMap); for (Map.EntryString, Integer entry : snapshot.entrySet()) { // 处理快照安全 }但注意这个拷贝本身也是弱一致性的它拷贝时的数据是那一刻的状态但拷贝过程中可能有并发修改。不过对于大多数业务来说这种程度的一致性已经够用了。4.4 遍历中的空值问题HashMap允许key和value都为null但ConcurrentHashMap不允许任何一方为nullTreeMap不允许key为null但value可以为nullLinkedHashMap跟HashMap一样都允许。这意味着你在遍历时如果某个value是null用entry.getValue().someMethod()就会NPE。一个稳妥的做法是使用Map.getOrDefault或者在遍历时判空。另外如果业务上不允许空值建议在put的时候就用Objects.requireNonNull(value)把问题挡在入口处而不是在遍历时去判断。5. 遍历源码级分析JDK里HashMap的迭代器究竟做了什么5.1 HashIterator的nextNode逻辑进入正题HashMap的迭代器实现非常有代表性。它内部有一个HashIterator类所有的迭代器KeyIterator、ValueIterator、EntryIterator都继承自它。abstract class HashIterator { NodeK,V next; // next entry to return NodeK,V current; // current entry int expectedModCount; // for fast-fail int index; // current slot HashIterator() { expectedModCount modCount; NodeK,V[] t table; current next null; index 0; if (t ! null size 0) { do {} while (index t.length (next t[index]) null); } } public final boolean hasNext() { return next ! null; } final NodeK,V nextNode() { NodeK,V[] t; NodeK,V e next; if (modCount ! expectedModCount) throw new ConcurrentModificationException(); if (e null) throw new NoSuchElementException(); if ((next (current e).next) null (t table) ! null) { do {} while (index t.length (next t[index]) null); } return e; } }这段代码是理解HashMap遍历性能的钥匙。构造方法里干了一件很关键的事它从哈希桶数组的第0个位置开始跳过所有为null的桶找到第一个非空节点。这样hasNext()才能判断是否还有下一个元素。nextNode()的逻辑是如果当前节点的next不为null继续沿着链表/红黑树走如果当前节点的next为null则跳到下一个非空的哈希桶。这其实就是在遍历哈希桶数组 每个桶内部的链表/红黑树这个复合结构。注意expectedModCount modCount在创建迭代器时就固定了。遍历中如果别人改了Map结构modCount变化nextNode()就会抛异常。5.2 链表退化成红黑树时遍历方式也变了当某个桶的链表长度超过8且数组长度超过64时链表会转成红黑树。但HashMap迭代器遍历红黑树时并不是走树的递归中序遍历而是通过TreeNode继承自LinkedHashMap.Entry的before/after指针来线性遍历。换句话说HashMap在链表转红黑树时会保留一个双向链表结构。TreeNode既是红黑树节点也是链表节点。迭代器走的是这个链表而不是树。所以即使某个桶已经是红黑树遍历它仍然是线性的复杂度O(n)不会因为树的深度增加而变慢。这个设计细节很多人不知道但它解释了为什么HashMap的遍历性能在单个桶数据很多时依然可以接受。5.3 为什么TreeSet迭代比HashSet慢3~5倍同理TreeMap的迭代走的是红黑树每个next()都需要从当前节点找到后继节点。如果当前节点有右子树就找右子树的最左节点否则向上回溯。这个过程涉及指针移动和路径回溯不像数组链表那样直接。我实测TreeMap迭代100万条数据大约需要150ms而HashMap只要50ms左右。这3倍的差距主要来自节点的指针跳跃和缓存不友好。所以在不需要有序性的场景别用TreeMap——这是性能优化里一个很常见的建议。6. 实际项目中最容易踩的遍历坑并发修改、NPE与排序问题6.1 多线程遍历不要并发修改Map结构前面说的ConcurrentModificationException大多是单线程内自己改自己引发的。但多线程场景也会有这个问题线程A在遍历HashMap线程B在put或removeA就会抛出ConcurrentModificationException。解决方案用ConcurrentHashMap替代HashMap或者对Map做加锁或者copy一份再遍历但注意即使改用ConcurrentHashMap遍历过程中看到的数据也不是严格的快照可能出现遍历了A、B、C中途另一个线程删了B又加了D最终遍历结果是A、C、D这种弱一致效果。如果业务不允许这种情况那你就需要手动拍快照。6.2 遍历时的NPEvalues为null的业务判断假设你有一个MapString, List 遍历时想统计每个key的列表大小for (Map.EntryString, ListString entry : map.entrySet()) { int size entry.getValue().size(); // 如果value为null这里就NPE }有的同事偷懒直接把put(key, null)放进去了遍历时立刻爆炸。比较好的做法是put的时候就不允许null或者遍历时统一处理for (Map.EntryString, ListString entry : map.entrySet()) { ListString list entry.getValue(); if (list ! null !list.isEmpty()) { // 业务处理 } }6.3 排序键值对的两种常见姿势如果Map本身不是排好序的但业务上需要按key排序输出通常有两种做法用TreeMap重新存储遍历后放进List再排序MapString, Integer sortedMap new TreeMap(map);或者ListMap.EntryString, Integer entries new ArrayList(map.entrySet()); entries.sort(Map.Entry.comparingByKey()); for (Map.EntryString, Integer entry : entries) { // 已按key排好序 }如果按value排序只能用第二种entries.sort((e1, e2) - e2.getValue().compareTo(e1.getValue()));注意这里排序的是Map.Entry对象的List不是Map本身。如果你需要的是按value排序后仍然保持键值映射List循环是比较直观的方式。7. 盘点我自己用过的几种实际业务场景中的遍历模式7.1 缓存清理遍历过期判断我维护过一个本地缓存用ConcurrentHashMap存储value是一个带过期时间的对象。清理任务每5分钟跑一次long now System.currentTimeMillis(); cacheMap.entrySet().removeIf(entry - now - entry.getValue().getTimestamp() MAX_AGE);一行代码搞定简洁且不会踩并发修改的坑。ConcurrentHashMap的removeIf底层用的是它的弱一致性迭代器多线程下也不会抛异常。7.2 分组聚合统计订单列表按用户ID聚合金额MapString, BigDecimal userAmountMap new HashMap(); for (Order order : orderList) { userAmountMap.merge(order.getUserId(), order.getAmount(), BigDecimal::add); } for (Map.EntryString, BigDecimal entry : userAmountMap.entrySet()) { // 输出每个用户的订单总额 }merge方法比传统的containsKey判断put简洁得多而且天然支持并发。JDK 8都建议用merge或computeIfAbsent。再配合entrySet遍历输出整个流程非常顺手。7.3 前端渲染Map数据返回给前端一个有序Map比如按指定顺序展示字段MapString, Object result new LinkedHashMap(); result.put(code, 0); result.put(message, success); result.put(data, dataList);用LinkedHashMap而不是HashMap保证输出顺序和put顺序一致。遍历时for (Map.EntryString, Object entry : result.entrySet()) { // 按顺序处理 }这个场景在写接口返回结构时很常见。8. 给面试和写代码的最终建议8.1 面试怎么答遍历Map有几种方式面试官问这个问题通常不只是想听你列五种方式更想听你讲清楚这几种方式的区别和适用场景。我建议按这个顺序组织回答先说结论有entrySet、keySet、values、Iterator、forEach Lambda五种然后按使用频率展开entrySet最常用keySet直观但需要额外的getvalues只在只需要值时用Iterator是唯一能在遍历中删除的正解forEach最简洁但要注意不能结构修改最后补充原理for-each本质是IteratorHashMap迭代器遍历的是数组链表/红黑树ConcurrentModificationException是fail-fast机制在保护迭代一致性如果被追问为什么keySet性能差直接点出每循环一次就多一次哈希查找这个关键这样回答既有广度也有深度能给面试官留下真的写过代码的印象。8.2 项目里怎么选遍历方式我的经验法则只需要value用values需要key和value优先entrySet遍历中要删用Iterator或removeIf代码简洁优先用forEach Lambda但要确认没有删除操作数据量小几百条以内怎么遍历都行可读性优先数据量大几十万条以上entrySet和values有明显优势避免keySetget8.3 一个我反复用的工具方法最后分享一个我写在自己项目里的工具方法用来把Map转成有序的字符串调试时打印特别方便public static String formatMap(MapString, Object map) { if (map null || map.isEmpty()) { return {}; } StringBuilder sb new StringBuilder({); map.forEach((k, v) - sb.append(k).append().append(v).append(, )); if (sb.length() 1) { sb.setLength(sb.length() - 2); } return sb.append(}).toString(); }它用forEachLambda实现一行一行拼接最后去掉末尾的逗号。这个方法在我排查接口返回时经常用到比起直接map.toString()自定义格式化更可控。其实遍历Map这个事说到底是两个层面的问题第一层是能不能遍历这个层面只要写得对五种方式都会。第二层是遍历得好不好这才是区分经验多与少的地方。理解底层的迭代器实现、理解fail-fast机制、理解不同Map实现的结构差异才能真正做到遇事不慌写出既正确又高效、还容易维护的代码。我在实际工作中见过太多因为不了解遍历细节而付出的成本一个线上OOM是缓存清理逻辑在遍历中抛了异常导致缓存没清掉一个接口超时是因为大数据量下用了keySetget一个诡异的脏数据问题是因为遍历ConcurrentHashMap时拿到了弱一致性的中间状态。这些坑都不深但看不见的时候它们会以最惨烈的方式让你重新认识Java的Map遍历。希望这篇能帮你少走这几条弯路。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

基于Spring Boot+Vue的影评管理系统设计与实现 2026/9/10 17:53:41

基于Spring Boot+Vue的影评管理系统设计与实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
Java日期比较全攻略:从Date到LocalDateTime的完整实践 2026/9/10 17:53:41

Java日期比较全攻略:从Date到LocalDateTime的完整实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
NVFuser 融合代码生成器:PyTorch TorchScript 的 GPU 算子融合后端 2026/9/10 17:53:41

NVFuser 融合代码生成器:PyTorch TorchScript 的 GPU 算子融合后端

NVFuser 融合代码生成器:PyTorch TorchScript 的 GPU 算子融合后端 【免费下载链接】pytorch Tensors and Dynamic neural networks in Python with strong GPU acceleration 项目地址: https://gitcode.com/GitHub_Trending/py/pytorch NVFuser 是 PyTorch …

阅读更多 →
随机森林回归实战:从数据预处理到模型调优全解析 2026/9/10 17:53:41

随机森林回归实战:从数据预处理到模型调优全解析

简介:随机森林回归模型项目实战资料包,面向Python机器学习初学者及需要项目练习的开发者,完整演示了从问题定义、数据获取、数据清洗与预处理、EDA探索性分析、特征工程,到随机森林建模、模型评估与实际应用的标准化流程。压缩包共…

阅读更多 →
Qwen-Agent 是怎么把 100 页 PDF 读给 AI 的?文档分块与存储 3 个机制全解析 2026/9/10 17:53:41

Qwen-Agent 是怎么把 100 页 PDF 读给 AI 的?文档分块与存储 3 个机制全解析

Qwen-Agent 是怎么把 100 页 PDF 读给 AI 的?文档分块与存储 3 个机制全解析 【免费下载链接】Qwen-Agent Agent framework and applications built upon Qwen>3.0, featuring Function Calling, MCP, Code Interpreter, RAG, Chrome extension, etc. 项目地址…

阅读更多 →
JPEG-LS V2.2工业级无损压缩实战指南 2026/9/10 17:50:40

JPEG-LS V2.2工业级无损压缩实战指南

简介:本资源是JPEG-LS无损图像压缩标准(ISO/IEC 14495-1 / ITU-T T.87)的V2.2版本完整实现源码包,面向图像处理开发者、嵌入式算法工程师及多媒体编码学习者,解决无损压缩算法集成、编解码流程理解与底层优化实践等核心…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞