最新要闻
- 梅西进4强 雷军点赞:阿根廷门将神了 太给力
- 全球微速讯:苹果要大赚!消息称iPhone 15又涨价 高端万元起:华为Mate60等跟涨吗
- 阿根廷点球大战淘汰荷兰:梅西点射破门 追平巴蒂纪录网友纷祝贺
- 国际领先!中国天眼获得银河系气体高清图像:揭露恒星诞生到消亡
- 世界热讯:巴西点球大战3-5克罗地亚!无缘四强 内马尔赛后痛哭
- 最轻折叠屏OPPO Find N2来了!朱海舟:上手后你会WOW一下
- 当前热点-负债585.68亿、工资发不出:国美获黄光裕公司贷款1.5亿港元
- 天天快讯:NVIDIA力推的光追版《传送门》游戏被指代码糟糕:AMD显卡坑了
- 零百加速3.8秒马力暴躁 蔚来全系车型试驾会郑州站开启
- 当前观点:后矿难时代 显卡价格仍居高不下
- 天天快消息!布洛芬不用抢 中国产能全球第一:一家公司就够33亿人用
- 世界即时:突发!特斯拉中国工厂将停产Model Y
- 世界速看:一箱油能跑1200公里!比亚迪护卫舰07上市 20.28万起
- 当前通讯!雷军再谈小米13徕卡影像:非常自豪 你一定会被震撼到
- 【天天时快讯】我 一个程序员 靠玩ChatGPT年薪210万
- 世界看点:DX9性能大涨80% Intel驱动打鸡血原因找到了:做法很聪明
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
天天热点评!环形队列、 条带环形队列 Striped-RingBuffer (史上最全)
文章很长,而且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录 博客园版为您奉上珍贵的学习资源 :
免费赠送 :《尼恩Java面试宝典》持续更新+ 史上最全 + 面试必备 2000页+ 面试必备 + 大厂必备 +涨薪必备免费赠送 经典图书:《Java高并发核心编程(卷1)加强版》面试必备 + 大厂必备 +涨薪必备 加尼恩免费领免费赠送 经典图书:《Java高并发核心编程(卷2)加强版》面试必备 + 大厂必备 +涨薪必备 加尼恩免费领免费赠送 经典图书:《Java高并发核心编程(卷3)加强版》面试必备 + 大厂必备 +涨薪必备 加尼恩免费领免费赠送 经典图书:《尼恩Java面试宝典 最新版》 面试必备 + 大厂必备 +涨薪必备 加尼恩免费领免费赠送 资源宝库: Java 必备 百度网盘资源大合集 价值>10000元 加尼恩领取
(相关资料图)
高性能 BoundedBuffer 条带环形队列
Caffeine 源码中,用到几个高性能数据结构要讲
- 一个是 条带环状 队列 (超高性能、无锁队列)
- 一个是mpsc队列 (超高性能、无锁队列)
- 一个是 多级时间轮
这里给大家 介绍 环形队列、 条带环形队列 Striped-RingBuffer 。
剩下的两个结构, 稍后一点 ,使用专门的 博文介绍。
CAS 的优势与核心问题
由于JVM重量级锁使用了Linux内核态下的互斥锁(Mutex),这是重量级锁开销很大的原因。
抢占与释放的过程中,涉及到 进程的 用户态和 内核态, 进程的 用户空间 和内核空间之间的切换, 性能非常低。
而CAS进行自旋抢锁,这些CAS操作都处于用户态下,进程不存在用户态和内核态之间的运行切换,因此JVM轻量级锁开销较小。这是 CAS 的优势。
但是, 任何事情,都有两面性。
CAS 的核心问题是什么呢?
在争用激烈的场景下,会导致大量的CAS空自旋。
比如,在大量的线程同时并发修改一个AtomicInteger时,可能有很多线程会不停地自旋,甚至有的线程会进入一个无限重复的循环中。
大量的CAS空自旋会浪费大量的CPU资源,大大降低了程序的性能。
除了存在CAS空自旋之外,在SMP架构的CPU平台上,大量的CAS操作还可能导致“总线风暴”,具体可参见《Java高并发核心编程 卷2 加强版》第5章的内容。
在高并发场景下如何提升CAS操作性能/ 解决CAS恶性空自旋 问题呢?
较为常见的方案有两种:
- 分散操作热点、
- 使用队列削峰。
比如,在自增的场景中, 可以使用LongAdder替代AtomicInteger。
这是一种 分散操作热点 ,空间换时间 方案,
也是 分而治之的思想。
以空间换时间:LongAdder 以及 Striped64
Java 8提供一个新的类LongAdder,以空间换时间的方式提升高并发场景下CAS操作性能。
LongAdder核心思想就是热点分离,与ConcurrentHashMap的设计思想类似:将value值分离成一个数组,当多线程访问时,通过Hash算法将线程映射到数组的一个元素进行操作;而获取最终的value结果时,则将数组的元素求和。
最终,通过LongAdder将内部操作对象从单个value值“演变”成一系列的数组元素,从而减小了内部竞争的粒度。LongAdder的演变如图3-10所示。
图3-10 LongAdder的操作对象由单个value值“演变”成了数组
LongAdder的分治思想和架构
LongAdder的操作对象由单个value值“演变”成了数组
LongAdder 继承了 Striped64,核心源码在 Striped64中。
条带累加Striped64的结构和源码
/** * A package-local class holding common representation and mechanics * for classes supporting dynamic striping on 64bit values. The class * extends Number so that concrete subclasses must publicly do so. */@SuppressWarnings("serial")abstract class Striped64 extends Number { /** * Padded variant of AtomicLong supporting only raw accesses plus CAS. * * JVM intrinsics note: It would be possible to use a release-only * form of CAS here, if it were provided. */ @sun.misc.Contended static final class Cell { volatile long value; Cell(long x) { value = x; } final boolean cas(long cmp, long val) { return UNSAFE.compareAndSwapLong(this, valueOffset, cmp, val); } // Unsafe mechanics private static final sun.misc.Unsafe UNSAFE; private static final long valueOffset; static { try { UNSAFE = sun.misc.Unsafe.getUnsafe(); Class> ak = Cell.class; valueOffset = UNSAFE.objectFieldOffset (ak.getDeclaredField("value")); } catch (Exception e) { throw new Error(e); } } } /** Number of CPUS, to place bound on table size */ static final int NCPU = Runtime.getRuntime().availableProcessors(); /** * Table of cells. When non-null, size is a power of 2. */ transient volatile Cell[] cells; /** * Base value, used mainly when there is no contention, but also as * a fallback during table initialization races. Updated via CAS. */ transient volatile long base; /** * Spinlock (locked via CAS) used when resizing and/or creating Cells. */ transient volatile int cellsBusy; /** * Package-private default constructor */ Striped64() { }
以上源码的特别复杂,请参见 《Java高并发核心编程 卷2 加强版》
BoundedBuffer 的核心源码
/** * A striped, non-blocking, bounded buffer. * * @author ben.manes@gmail.com (Ben Manes) * @param the type of elements maintained by this buffer */final class BoundedBuffer extends StripedBuffer
它是一个 striped、非阻塞、有界限的 buffer,继承于StripedBuffer类。
下面看看StripedBuffer的实现:
/** * A base class providing the mechanics for supporting dynamic striping of bounded buffers. This * implementation is an adaption of the numeric 64-bit {@link java.util.concurrent.atomic.Striped64} * class, which is used by atomic counters. The approach was modified to lazily grow an array of * buffers in order to minimize memory usage for caches that are not heavily contended on. * * @author dl@cs.oswego.edu (Doug Lea) * @author ben.manes@gmail.com (Ben Manes) */abstract class StripedBuffer implements Buffer
StripedBuffer (条带缓冲)的架构
解决CAS恶性空自旋的有效方式之一是以空间换时间,较为常见的方案有两种:
- 分散操作热点、
- 使用队列削峰。
这个StripedBuffer设计的思想是跟Striped64类似的,通过扩展结构把分散操作热点(/竞争热点分离)。
具体实现是这样的,StripedBuffer维护一个Buffer[]数组,叫做table,每个元素就是一个RingBuffer,
每个线程用自己id属性作为 hash 值的种子产生hash值,这样就相当于每个线程都有自己“专属”的RingBuffer,
在hash分散很均衡的场景下,就不会尽量的降低竞争,避免空自旋,
、
看看StripedBuffer的属性
/** Table of buffers. When non-null, size is a power of 2. *///RingBuffer数组transient volatile Buffer @Nullable[] table;//当进行resize时,需要整个table锁住。tableBusy作为CAS的标记。static final long TABLE_BUSY = UnsafeAccess.objectFieldOffset(StripedBuffer.class, "tableBusy");static final long PROBE = UnsafeAccess.objectFieldOffset(Thread.class, "threadLocalRandomProbe");/** Number of CPUS. */static final int NCPU = Runtime.getRuntime().availableProcessors();/** The bound on the table size. *///table最大sizestatic final int MAXIMUM_TABLE_SIZE = 4 * ceilingNextPowerOfTwo(NCPU);/** The maximum number of attempts when trying to expand the table. *///如果发生竞争时(CAS失败)的尝试次数static final int ATTEMPTS = 3;/** Table of buffers. When non-null, size is a power of 2. *///核心数据结构transient volatile Buffer @Nullable[] table;/** Spinlock (locked via CAS) used when resizing and/or creating Buffers. */transient volatile int tableBusy;/** CASes the tableBusy field from 0 to 1 to acquire lock. */final boolean casTableBusy() { return UnsafeAccess.UNSAFE.compareAndSwapInt(this, TABLE_BUSY, 0, 1);}/** * Returns the probe value for the current thread. Duplicated from ThreadLocalRandom because of * packaging restrictions. */static final int getProbe() { return UnsafeAccess.UNSAFE.getInt(Thread.currentThread(), PROBE);}
offer方法,当没初始化或存在竞争时,则扩容为 2 倍。最大为不小于 CPU核数的 2幂值。
/** * The bound on the table size. */ static final int MAXIMUM_TABLE_SIZE = 4 * ceilingPowerOfTwo(NCPU);
实际是调用RingBuffer的 offer 方法,把数据追加到RingBuffer后面。
@Overridepublic int offer(E e) { int mask; int result = 0; Buffer buffer; //是否不存在竞争 boolean uncontended = true; Buffer[] buffers = table //是否已经初始化 if ((buffers == null) || (mask = buffers.length - 1) < 0 //用thread的随机值作为hash值,得到对应位置的RingBuffer || (buffer = buffers[getProbe() & mask]) == null //检查追加到RingBuffer是否成功 || !(uncontended = ((result = buffer.offer(e)) != Buffer.FAILED))) { //其中一个符合条件则进行扩容 expandOrRetry(e, uncontended); } return result;}/** * Handles cases of updates involving initialization, resizing, creating new Buffers, and/or * contention. See above for explanation. This method suffers the usual non-modularity problems of * optimistic retry code, relying on rechecked sets of reads. * * @param e the element to add * @param wasUncontended false if CAS failed before call *///这个方法比较长,但思路还是相对清晰的。@SuppressWarnings("PMD.ConfusingTernary")final void expandOrRetry(E e, boolean wasUncontended) { int h; if ((h = getProbe()) == 0) { ThreadLocalRandom.current(); // force initialization h = getProbe(); wasUncontended = true; } boolean collide = false; // True if last slot nonempty for (int attempt = 0; attempt < ATTEMPTS; attempt++) { Buffer[] buffers; Buffer buffer; int n; if (((buffers = table) != null) && ((n = buffers.length) > 0)) { if ((buffer = buffers[(n - 1) & h]) == null) { if ((tableBusy == 0) && casTableBusy()) { // Try to attach new Buffer boolean created = false; try { // Recheck under lock Buffer[] rs; int mask, j; if (((rs = table) != null) && ((mask = rs.length) > 0) && (rs[j = (mask - 1) & h] == null)) { rs[j] = create(e); created = true; } } finally { tableBusy = 0; } if (created) { break; } continue; // Slot is now non-empty } collide = false; } else if (!wasUncontended) { // CAS already known to fail wasUncontended = true; // Continue after rehash } else if (buffer.offer(e) != Buffer.FAILED) { break; } else if (n >= MAXIMUM_TABLE_SIZE || table != buffers) { collide = false; // At max size or stale } else if (!collide) { collide = true; } else if (tableBusy == 0 && casTableBusy()) { try { if (table == buffers) { // Expand table unless stale table = Arrays.copyOf(buffers, n << 1); } } finally { tableBusy = 0; } collide = false; continue; // Retry with expanded table } h = advanceProbe(h); } else if ((tableBusy == 0) && (table == buffers) && casTableBusy()) { boolean init = false; try { // Initialize table if (table == buffers) { @SuppressWarnings({"unchecked", "rawtypes"}) Buffer[] rs = new Buffer[1]; rs[0] = create(e); table = rs; init = true; } } finally { tableBusy = 0; } if (init) { break; } } }}
环形队列
我们知道,队列伴随着生产和消费,而队列一般也是由数组或链表来实现的,
队列是一个先进先出的结构,那么随着游标在数组上向后移动,
前面已经消费了的数据已没有意义,但是他们依然占据着内存空间,浪费越来越大,
所以:环形队列就很好的解决了这个问题。
环形队列是在实际编程极为有用的数据结构,它采用数组的线性空间,数据组织简单,能很快知道队列是否满或空,能以很快速度的来存取数据。
从顺时针看,环形队列 有队头 head 和队尾 tail。
生产的流程是:
生产者顺时针向队尾 tail 插入元素,这会导致 head 位置不变,tail 位置在后移;
消费的流程是:
消费者则从队头 head 开始消费,这会导致 head 向后移动,而tail 位置不变,如果队列满了就不能写入。
环形队列的特点:
队头 head 和队尾 tail 的位置是不定的,位置一直在循环流动,空间就被重复利用起来了。
因为有简单高效的原因,甚至在硬件都实现了环形队列.。
环形队列广泛用于网络数据收发,和不同程序间数据交换(比如内核与应用程序大量交换数据,从硬件接收大量数据)均使用了环形队列。
环形队列的参考实现
下面的环形队列, 参考了 缓存之王 Caffeine 源码中的 命名
package com.crazymakercircle.queue;public class SimpleRingBufferDemo { public static void main(String[] args) { //创建一个环形队列 SimpleRingBuffer queue = new SimpleRingBuffer(4); queue.offer(11); queue.offer(12); queue.offer(13); System.out.println("queue = " + queue); int temp = queue.poll(); System.out.println("temp = " + temp); System.out.println("queue = " + queue); temp = queue.poll(); System.out.println("temp = " + temp); System.out.println("queue = " + queue); temp = queue.poll(); System.out.println("temp = " + temp); System.out.println("queue = " + queue); }}class SimpleRingBuffer { private int maxSize;//表示数组的最大容量 private int head; // 模拟 缓存之王 Caffeine 源码命名 //head就指向队列的第一个元素,也就是arr[head]就是队列的第一个元素 //head的初始值=0 private int tail; // 模拟 缓存之王 Caffeine 源码命名 //tail指向队列的最后一个元素的后一个位置,因为希望空出一个空间做为约定 //tail的初始化值=0 private int[] buffer;//该数据用于存放数据 public SimpleRingBuffer(int arrMaxSize) { maxSize = arrMaxSize; buffer = new int[maxSize]; } //判断队列是否满 public boolean isFull() { return (tail + 1) % maxSize == head; } //判断队列是否为空 public boolean isEmpty() { return tail == head; } //添加数据到队列 public void offer(int n) { //判断队列是否满 if (isFull()) { System.out.println("队列满,不能加入数据"); return; } //直接将数据加入 buffer[tail] = n; //将tail后移,这里必须考虑取模 tail = (tail + 1) % maxSize; } //获取队列的数据,出队列 public int poll() { //判断队列是否空 if (isEmpty()) { //通过抛出异常 throw new RuntimeException("队列空,不能取数据"); } //这里需要分析出head是指向队列的第一个元素 //1.先把head对应的值保留到一个临时变量 //2.将head后移,考虑取模 //3.将临时保存的变量返回 int value = buffer[head]; head = (head + 1) % maxSize; return value; } //求出当前队列有效数据的个数 public int size() { return (tail + maxSize - head) % maxSize; } @Override public String toString() { return String.format("head=%d , tail =%d\n",head,tail); }}
测试的结果
环形核心的结构和流程说明
约定head指向队列的第一个元素,
也就是说data[head]就是队头数据,head初始值为0。
约定tail指向队列的最后一个元素的后一个位置,
也就是说data[tail-1]就是队尾数据,tail初始值为0。
队列满的条件是:
( tail+1 )% maxSize == head
队列空的条件是:
tail == head
队列中的元素个数为:
( tail + maxsize - head) % maxSize
有效数据只有maxSize-1个
因为tail指向队尾的后面一个位置,这个位置就不能存数据,因此有效数据只有maxSize-1个
环形队列核心操作:判满
写入的时候,当前位置的下一位置是(tail+1)% maxSize
由图可知:
当head刚好指向tail的下一个位置时队列满,而tail的下一个位置是 (tail+1)% maxSize,
所以当( tail + 1 )% maxSize == head 时,队列就满了。
环形队列核心操作:判空
队列为空的情况如下图所示,当队头队尾都指向一个位置,即 head == tail时,队列为空。
当head == tail时,队列为空
因为tail指向队尾的后面一个位置,这个位置就不能存数据,
因此, 环形队列的有效数据只有maxSize-1个
RingBuffer 源码
caffeine源码中, 注意RingBuffer是BoundedBuffer的内部类。
/** The maximum number of elements per buffer. */static final int BUFFER_SIZE = 16;// Assume 4-byte references and 64-byte cache line (16 elements per line)//256长度,但是是以16为单位,所以最多存放16个元素static final int SPACED_SIZE = BUFFER_SIZE << 4;static final int SPACED_MASK = SPACED_SIZE - 1;static final int OFFSET = 16;//RingBuffer数组final AtomicReferenceArray buffer; //插入方法 @Override public int offer(E e) { long head = readCounter; long tail = relaxedWriteCounter(); //用head和tail来限制个数 long size = (tail - head); if (size >= SPACED_SIZE) { return Buffer.FULL; } //tail追加16 if (casWriteCounter(tail, tail + OFFSET)) { //用tail“取余”得到下标 int index = (int) (tail & SPACED_MASK); //用unsafe.putOrderedObject设值 buffer.lazySet(index, e); return Buffer.SUCCESS; } //如果CAS失败则返回失败 return Buffer.FAILED; } //用consumer来处理buffer的数据 @Override public void drainTo(Consumer consumer) { long head = readCounter; long tail = relaxedWriteCounter(); //判断数据多少 long size = (tail - head); if (size == 0) { return; } do { int index = (int) (head & SPACED_MASK); E e = buffer.get(index); if (e == null) { // not published yet break; } buffer.lazySet(index, null); consumer.accept(e); //head也跟tail一样,每次递增16 head += OFFSET; } while (head != tail); lazySetReadCounter(head); }
注意,ring buffer 的 size(固定是 16 个)是不变的,变的是 head 和 tail 而已。
Striped-RingBuffer 有如下特点:
总的来说 Striped-RingBuffer 有如下特点:
- 使用 Striped-RingBuffer来提升对 buffer 的读写
- 用 thread 的 hash 来避开热点 key 的竞争
- 允许写入的丢失
推荐阅读:
《尼恩Java面试宝典》
《Springcloud gateway 底层原理、核心实战 (史上最全)》
《sentinel (史上最全)》
《分库分表 Sharding-JDBC 底层原理、核心实战(史上最全)》
《分布式事务 (秒懂)》
《缓存之王:Caffeine 源码、架构、原理(史上最全,10W字 超级长文)》
《缓存之王:Caffeine 的使用(史上最全)》
《Java Agent 探针、字节码增强 ByteBuddy(史上最全)》
《Docker原理(图解+秒懂+史上最全)》
《Redis分布式锁(图解 - 秒懂 - 史上最全)》
《Zookeeper 分布式锁 - 图解 - 秒懂》
《Zookeeper Curator 事件监听 - 10分钟看懂》
《Netty 粘包 拆包 | 史上最全解读》
《Netty 100万级高并发服务器配置》
《Springcloud 高并发 配置 (一文全懂)》
参考文献
疯狂创客圈 JAVA 高并发 总目录
ThreadLocal(史上最全)https://www.cnblogs.com/crazymakercircle/p/14491965.html
3000页《尼恩 Java 面试宝典 》的 35个面试专题 :https://www.cnblogs.com/crazymakercircle/p/13917138.html
价值10W的架构师知识图谱https://www.processon.com/view/link/60fb9421637689719d246739
4、尼恩 架构师哲学https://www.processon.com/view/link/616f801963768961e9d9aec8
5、尼恩 3高架构知识宇宙https://www.processon.com/view/link/635097d2e0b34d40be778ab4
Guava Cache主页:https://github.com/google/guava/wiki/CachesExplained
Caffeine的官网:https://github.com/ben-manes/caffeine/wiki/Benchmarks
https://gitee.com/jd-platform-opensource/hotkey
https://developer.aliyun.com/article/788271?utm_content=m_1000291945
https://b.alipay.com/page/account-manage-oc/approval/setList
Caffeine: https://github.com/ben-manes/caffeine
这里: https://albenw.github.io/posts/df42dc84/
Benchmarks: https://github.com/ben-manes/caffeine/wiki/Benchmarks
-
天天热点评!环形队列、 条带环形队列 Striped-RingBuffer (史上最全)
文章很长,而且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录博客园版为您奉上珍贵的学习资源:免...
来源: 天天热点评!环形队列、 条带环形队列 Striped-RingBuffer (史上最全)
梅西进4强 雷军点赞:阿根廷门将神了 太给力
全球微速讯:苹果要大赚!消息称iPhone 15又涨价 高端万元起:华为Mate60等跟涨吗
天天快资讯:深度学习基础课:最大池化层的前向传播推导
阿根廷点球大战淘汰荷兰:梅西点射破门 追平巴蒂纪录网友纷祝贺
国际领先!中国天眼获得银河系气体高清图像:揭露恒星诞生到消亡
世界热讯:巴西点球大战3-5克罗地亚!无缘四强 内马尔赛后痛哭
今日播报!Python装饰器与迭代器的学习教程
全球快资讯:你必须记住的30个CSS选择器?
最轻折叠屏OPPO Find N2来了!朱海舟:上手后你会WOW一下
当前热点-负债585.68亿、工资发不出:国美获黄光裕公司贷款1.5亿港元
天天快讯:NVIDIA力推的光追版《传送门》游戏被指代码糟糕:AMD显卡坑了
零百加速3.8秒马力暴躁 蔚来全系车型试驾会郑州站开启
世界短讯!MAUI新生5.2-样式外观:控件状态样式VisualState
python实现简单的商品数据管理系统
全球动态:asp.net core 基于Cookies的认证,自定义认证方案
全球新消息丨nginx中的正则表达式,location路径匹配规则和优先级
当前观点:后矿难时代 显卡价格仍居高不下
环球通讯!Java校验自定义枚举值
全球观天下!第一百一十一篇:基本引用类型Date
天天快消息!布洛芬不用抢 中国产能全球第一:一家公司就够33亿人用
天天短讯!BLOG-3总结
世界即时:突发!特斯拉中国工厂将停产Model Y
世界速看:一箱油能跑1200公里!比亚迪护卫舰07上市 20.28万起
当前通讯!雷军再谈小米13徕卡影像:非常自豪 你一定会被震撼到
【天天时快讯】我 一个程序员 靠玩ChatGPT年薪210万
世界看点:DX9性能大涨80% Intel驱动打鸡血原因找到了:做法很聪明
关注:南京一外卖小哥逆行撞劳斯莱斯 网友:几十年外卖白送了
今日快看!全球首架C919正式交付 中国搞这款大飞机有多不容易?
AI画作拍出110万高价创纪录!实测百度AI作画 效果惊艳
主人吃螺蛳粉:猫咪被臭到自闭
世界观速讯丨19岁少女无法走路 竟是因为它?国家早已明令禁止!
rsync远程同步
世界观焦点:AMD RX 7900 XTX渲染跑分性能曝光:感觉和RTX 4080两个时代
【热闻】国内电影票房已达285亿 《阿凡达2》成救命稻草:高价被指吃相难看
世界热推荐:为什么日本人更健康长寿?这12个“秘诀”值得借鉴
小米13 Pro长焦表现一绝:10cm至无穷远均可合焦
【报资讯】网传辽宁一有轨电车碾压电动自行车 官方回应:系剐蹭、人无碍
netmiko+textfsm自动统计交换机端口模块型号数量与闲置模块
【全球独家】【网关开发】4.Openresty 使用events插件进行事件通知
世界新消息丨蒟蒻颤抖:AI打信奥赛,三分之二赛题一遍过
【求助帖】从技术转为项目经理后,如何快速进入角色?
angr_ctf——从0学习angr(四):库操作和溢出漏洞利用
【世界速看料】新一代广汽本田皓影官图发布:大嘴变方嘴、可选7座
《原神》获TGA“玩家之声”奖!官方发800原石:全体都有
世界新动态:一部车骑10年!绿源推出INNO9-lite电动自行车:新国标 80km续航
天天快消息!NVIDIA发布527.56显卡驱动程序:DLSS 3游戏性能更强了
天天最资讯丨站起来了!哈弗H6插电混动版11月销量首超4000:直逼问界M5
焦点速递!CSS绝对定位7大应用场景实战案例分享
教你用CSS实现表单部件
环球热议:物联网平台在AIoT领域8大场景应用
东航官宣全球第一架C919商业首飞时间!这7大城市有福了
打爆丰田、本田混动SUV 比亚迪护卫舰07上市:20.28万起
天天微资讯!换代!AMD锐龙9 7950X3D来了:游戏性能比酷睿i9-13900K高出33%
【速看料】全国5G网络接入速率出炉:北京、上海都没抢到第一 移动最快
【世界新要闻】上线7年无敌手!《王者荣耀》11月吸金超13亿元:蝉联销冠
观点:MYSQL 1 DAY
世界微速讯:智能PDU,网络远程管理电源能耗提升配电效率
当前滚动:“云办公”如何用任务协同工具搞定项目和团队管理?
今日聚焦!SSM整合(spring-springmvc-mybatis)之CRUD
焦点日报:又拓新业务 比亚迪全新皮卡谍照曝光:DM混动没跑了
热点!不掉绒、无静电!史努比牛奶绒床品四件套大促:券后99元
天天快讯:一箭十四星 捷龙三号运载火箭首飞发射成功:海陆两用
焦点快播:QQ等级全球第一咋做到的?本人回应让网友羡慕:小时候家里开网吧
官方“挖墙脚”?网易《逆水寒》宣布推出“网易魔兽老兵服”
资讯:vscode使用chatGPT
全球滚动:我与 ChatGPT 讨论了面向对象语言 中,关于动态调用的问题
快播:第三方登录组件-JustAuth
【环球报资讯】BI智慧仓储,带你体验数字化仓储物流管理
环球今亮点!把ipa文件上传到App Store教程步骤
每日热讯!易基因:简化甲基化测序(RRBS)在植物生态表观基因组学中的机遇和局限|深度综述
当前聚焦:记.net framework php接口 返回数据格式问题 请求接口远程服务器返回错误: (500) 内部服务器错误
ChatGPT 大白话 SmartIDE
Zabbix与乐维监控对比分析(三)——对象管理篇
全球报道:专访|开源之夏最佳质量奖 Apache RocketMQ Committer 黄章衡
世界热消息:.net6制作让同事不能上网的arp欺骗工具
每日热门:如何利用 A/B 实验提升产品用户留存? 看字节实战案例给你答案!
chatGPT辣么火,你却不会注册
每日速讯:2022最新上传ipa到appstore的步骤说明
怎么在电脑上查看iPhone定位?iphone定位不准怎么校正?
怎么验证windows是不是正版?验证windows正版的方法有哪些?
光大银行信用卡额度一般是多少?光大银行信用卡怎么查询进度?
银行卡号泄露有危险吗?银行卡号泄露挂失有用吗?
空调怎么省电?空调省电的正确用法有哪些?
word文档怎么做思维导图?word文档怎么做小抄?
宏碁4750g怎么进入bios?宏碁4750G需要哪些驱动?
电视机顶盒怎么破解?电视机顶盒哪个牌子好用?
诺基亚710上市价格是多少?诺基亚710手机现在能用吗?
天然气热值是多少大卡?天然气热值换算表
环球热议:行为管理(锐捷业务软件篇)
焦点报道:直播间疯狂刷礼物可能是在洗钱:网络水军用千部手机给主播打赏 最多刷10亿元
国产操作系统deepin推送20.8版本:wine应用开启速度获得提升
联想PC小新桌面助手上线:实用性堪比手机控制中心
无叶无根无枝条的花你见过没?曾消失30年:开败后就变黑
世界今亮点!《原神》《幻塔》都败了!《MARVEL SNAP》摘得TGA 2022年度最佳手游
【全球速看料】BI智慧仓储行业应用方案,让你的仓储物流不再复杂
【全球播资讯】RTX 3050加持 联想轻薄旗舰本小新Pro 16史低价:5799元
【聚看点】特斯拉左转失控 车主称刹车和方向盘突然变硬:官方售后回应尴尬
观热点:海外经销商顶不住:RTX 4080英国又降价 轻松降近900元还会继续
焦点播报:首批车主反馈良好!恒驰汽车回应停工停产传闻:恒驰5按计划交付