【2024秋招】腾讯云智武汉后端开发一面 2023-9-20

1 java

1.1 hashMap

1.2 哈希冲突的解决方法

1.3 讲解一下CAS的aba问题

1.4 concurrentHashMap的并发方案为什么要使用cas

ConcurrentHashMap 是 Java 并发包 java.util.concurrent 中的一个重要组件,用于提供高并发、高性能、线程安全的哈希映射。为了达到这样的性能,ConcurrentHashMap 在其内部实现中使用了多种并发策略,其中 CAS (Compare-And-Swap) 是其关键技术之一。以下是使用 CAS 的原因:

  1. 无锁操作:CAS 是一种无锁操作,它允许多个线程在没有互斥量或锁的情况下对数据进行并发更新。这提高了整体性能,因为线程不需要等待锁,也不会因为锁竞争而上下文切换。

  2. 精细化锁定:尽管 ConcurrentHashMap 使用了分段锁技术(在 Java 8 之前)和 Node 级别的锁定(在 Java 8 及以后)来降低锁的竞争,但某些操作,如计数器增加或某些节点状态的更新,可以通过 CAS 完成,以避免使用传统锁。

  3. 性能优势:相对于重量级锁,CAS 在高并发情况下通常提供更好的性能,尤其是当锁竞争较低时。CAS 的开销相对较小,这使得在高并发场景下,ConcurrentHashMap 的吞吐量和响应时间都有所提高。

  4. 线程安全的延迟初始化ConcurrentHashMap 中的某些结构,如 table 数组,可以使用 CAS 进行线程安全的延迟初始化,这确保了只有一个线程可以成功地初始化数组,而其他线程则会看到已经初始化的版本。

  5. 实现无锁读ConcurrentHashMap 允许完全无锁的读取操作。为了实现这一点,并保持数据的一致性,CAS 操作在更新数据时发挥了关键作用。

需要注意的是,尽管 CAS 提供了许多优势,但它并不是万能的。CAS 操作可能会因为其他线程的干扰而失败,导致自旋。但在实际应用中,由于 ConcurrentHashMap 的数据结构和策略选择,CAS 失败的次数通常很少,所以它仍然是一个非常高效的机制。

总的来说,CAS 是 ConcurrentHashMap 达到高并发性能的关键技术之一。

1.5 java里面有没有cas这个相关的类

是的,Java中有与CAS(Compare-and-Swap)操作相关的类,它位于java.util.concurrent.atomic包中。这个包提供了一些原子类,它们使用无锁的机制(通常是基于CAS操作)来支持线程安全的加法、递增、递减等操作。

以下是一些常用的原子类:

  1. AtomicInteger: 一个整数值,可以被多个线程原子地更新。

    • 主要方法:get(), set(int newValue), getAndIncrement(), getAndDecrement(), compareAndSet(int expect, int update)等。
  2. AtomicLong: 类似于AtomicInteger,但用于长整数。

  3. AtomicBoolean: 一个布尔值,可以被多个线程原子地更新。

  4. AtomicReference<V>: 一个对象引用,支持原子性更新。

例如,使用AtomicInteger的CAS操作:

import java.util.concurrent.atomic.AtomicInteger;public class CASDemo {public static void main(String[] args) {AtomicInteger atomicInt = new AtomicInteger(0);// CAS操作boolean updated = atomicInt.compareAndSet(0, 1);  // 如果当前值为0,那么更新为1System.out.println(updated);  // 输出: trueSystem.out.println(atomicInt.get());  // 输出: 1updated = atomicInt.compareAndSet(0, 2);  // 由于当前值为1,这个CAS操作将失败System.out.println(updated);  // 输出: falseSystem.out.println(atomicInt.get());  // 输出: 1}
}

这些原子类可以在高并发环境中提供性能优势,因为它们通常不需要使用重的锁。然而,它们的使用必须小心,以确保算法的整体正确性。

1.6 java里的cas如何解决aba问题

是的,您触及了一个非常关键的点。compareAndSet操作确实是受到所谓的ABA问题的影响。ABA问题是指在一个线程读取某个值A、在另一个线程修改了这个值并将其设置为B然后又设置回A后,第一个线程再执行compareAndSet操作时,仍然会认为值没有变化。

但在上面的示例中,我们没有实际遇到ABA问题,因为这是一个简单的例子,仅展示了compareAndSet的基本使用。但在真实的多线程环境中,确实需要考虑ABA问题。

为了解决ABA问题,Java提供了AtomicStampedReference<V>类,它使用一个"stamp"(类似于版本号)来跟踪变量的更改。每次变量被修改时,stamp都会递增。这样,即使值回到了之前的状态,stamp也会是不同的,因此线程可以知道在它读取值之后发生了多少次修改。

例如:

import java.util.concurrent.atomic.AtomicStampedReference;public class CASDemo {public static void main(String[] args) {AtomicStampedReference<Integer> atomicRef = new AtomicStampedReference<>(0, 0);int stamp = atomicRef.getStamp();boolean updated = atomicRef.compareAndSet(0, 1, stamp, stamp + 1);System.out.println(updated);  // 输出: trueSystem.out.println(atomicRef.getReference());  // 输出: 1// 模拟ABA问题stamp = atomicRef.getStamp();atomicRef.compareAndSet(1, 2, stamp, stamp + 1);stamp = atomicRef.getStamp();atomicRef.compareAndSet(2, 0, stamp, stamp + 1);stamp = atomicRef.getStamp();updated = atomicRef.compareAndSet(0, 3, stamp - 2, stamp + 1);  // 尝试使用旧的stampSystem.out.println(updated);  // 输出: falseSystem.out.println(atomicRef.getReference());  // 输出: 0}
}

在上面的例子中,即使值回到了0,由于stamp的改变,我们仍然可以知道在这之前发生了其他的操作,因此可以避免ABA问题。

2 mysql

2.1 innodb和myIsam的区别

3 redis

3.1 你用过redis的什么数据结构

实现限流器时,可以选择不同的数据结构和策略,具体选择哪种取决于所需的限流策略和具体场景。以下是一些常见的限流策略和对应的推荐数据结构:

  1. 固定窗口限流

    • 数据结构: 计数器 (通常使用 String 或 Hash in Redis)
    • 实现: 每当有一个请求进来,都会将对应的计数器加一,并设置一个固定的过期时间。如果计数器超过了限制值,则拒绝请求。适合简单场景,但可能在窗口边界时出现请求高峰。
  2. 滑动窗口限流

    • 数据结构: 列表 (List in Redis) 或时间序列
    • 实现: 记录每次请求的时间戳。当请求进来时,移除早于当前时间窗口的时间戳,并检查列表/时间序列中的条目数量。如果超过了限制,则拒绝请求。这种方法相对平滑,不会在窗口边界时突然放行或拒绝大量请求。
  3. 漏桶限流

    • 数据结构: 队列
    • 实现: 将请求视为进入一个有固定容量的“桶”。如果桶满了,则拒绝新的请求。请求以固定的速率从桶中“漏出”。这种方法可以很好地应对突发流量。
  4. 令牌桶限流

    • 数据结构: 计数器
    • 实现: 有一个令牌生成器,以固定速率生成令牌,并放入令牌桶。当请求进来时,尝试从桶中取出一个令牌。如果桶中没有令牌,则拒绝请求。这种方法允许一定程度的突发流量,因为令牌可以累积到一定数量。

如果使用 Redis 来实现限流器,INCREXPIRELISTZSET 等操作都很有用。例如,使用 INCREXPIRE 可以轻松实现固定窗口限流;使用 LPUSHLTRIMEXPIRE 可以实现滑动窗口限流。

在选择数据结构和策略时,需要考虑应用的具体需求,例如限流的精度、是否允许突发流量、限流器的性能要求等因素。

3.2 redis的hash和string的区别是什么呢?不都是key-value嘛hash结构什么时候会用到呢

确实,Redis 的 String 和 Hash 都是基于 key-value 的数据结构,但它们的用途和特点有所不同。

  1. String 类型:

    • 是最简单的类型,每个 key 只对应一个 value。
    • value 可以是字符串、整数或浮点数。
    • 可以进行数学操作,例如增加、减少值。
    • 适用于存储简单的 key-value 数据,例如计数器、配置项、会话信息等。
  2. Hash 类型:

    • 每个 key 对应一个内部的 key-value 映射。这意味着 Hash 在 Redis 中实际上是一个嵌套的 key-value 结构,即 “field1” -> “value1”, “field2” -> “value2”。
    • 适用于存储对象或者多个相关的数据点。例如,一个用户对象可能有多个属性(如 “name”、“age”、“email”),这些都可以作为一个 Hash 的字段存储。
    • 对于部分更新或读取场景,Hash 更为高效。例如,你可以仅更新用户的 “email” 字段,而不需要获取和重新设置整个对象。
    • Hash 结构在存储小数据对象时,更为存储高效。

Hash 的应用场景:

  1. 存储对象: 例如,用户的属性、商品信息、文章的元数据等。
  2. 部分更新: 当需要经常更新某个对象的部分字段时,Hash 是一个很好的选择。
  3. 存储关联数据: 如果你有一系列相关的数据点,可以将它们存储为 Hash,这样你可以一次性取回所有相关数据。
  4. 存储小数据量的字段: Hash 在存储少量字段时,相对于其他数据结构,如 JSON 字符串存储在 String 类型中,更为存储高效。

总之,虽然 String 和 Hash 都是 key-value 结构,但 Hash 提供了一种更复杂的、嵌套的 key-value 结构,非常适合存储和管理对象或多个相关的数据点。

4 秒杀

4.1 etcd解决超卖问题,能说一下吗

4.2 如果db那边处理扣减失败怎么办呢(重要)

答:秒杀场景中,高并发和数据一致性是两个关键的挑战。当在扣减真实库存时数据库操作失败,可以采取以下策略和措施来处理:

  1. 重试机制:

    • 如果数据库操作失败是由于临时的网络波动或其他瞬时原因,可以考虑重试机制。
    • 但需要注意,过于频繁的重试可能会加剧系统的压力。因此,重试策略需要有最大重试次数和适当的延迟策略。
  2. 回滚库存:

    • 如果库存扣减失败,那么之前对预扣减的库存(例如在缓存中的预扣减)应当进行回滚,使其重新可用。
    • 这需要确保整个操作是原子性的,要么都成功,要么都失败。
  3. 异步补偿机制:

    • 使用消息队列或事件驱动的方法,将失败的扣减操作放入队列,后续通过异步补偿任务来重试。
    • 这样即使实时操作失败,后续也有机会保持数据的一致性。
  4. 告警机制:

    • 当库存扣减失败时,应立即触发告警,通知相关人员介入处理。
    • 监控系统和日志分析是在这种场景中的关键工具。
  5. 限流和降级:

    • 如果数据库压力过大导致操作失败,可以考虑启动限流策略,限制进一步的请求流量。
    • 同时,启用服务降级,例如临时关闭秒杀活动,或者将用户引导到一个简化的流程。
  6. 数据库优化:

    • 使用更高效的数据库操作,如批量更新,减少单点操作的数量。
    • 考虑数据库的分区、分片等策略,以便更好地扩展并处理大量请求。
  7. 使用分布式锁:

    • 在扣减库存的操作中使用分布式锁,确保在给定时刻只有一个操作在进行。
    • 这可以避免并发操作导致的数据不一致,但可能会降低系统的并发处理能力。
  8. 备份方案:

    • 如果主要的数据库操作持续失败,可以考虑启用备份方案,例如将请求转发到备用的数据库或服务。

秒杀场景下,应确保系统的韧性和可恢复性,以应对各种意外和故障。预期的失败和应对策略应在系统设计阶段就进行详细考虑。

4.3 我觉得可以将重试和回滚库存这两个策略结合起来

当然可以。将重试机制与库存回滚策略结合在秒杀场景中是一个很实用的做法。以下是一个结合两者的策略示例:

  1. 预扣减库存:

    • 当用户尝试购买时,首先在缓存或其他高速存储中预扣减库存。
    • 预扣减成功后,进行后续的数据库扣减操作。
  2. 数据库扣减与重试:

    • 尝试在数据库中扣减真实的库存。
    • 如果操作失败(可能是因为瞬时的网络问题、数据库繁忙等原因),则进入重试逻辑。
    • 在重试逻辑中,设置最大的重试次数,例如3次,每次重试之间设置适当的延迟,如500ms。
    • 如果在最大重试次数内仍然失败,则进入库存回滚策略。
  3. 库存回滚:

    • 对于刚刚预扣减的库存,在缓存或其他高速存储中进行库存的回滚操作,将其恢复到之前的数量。
    • 在这一步,也需要确保操作的原子性,确保数据的一致性。
  4. 用户反馈:

    • 如果经过重试仍然失败并执行了库存回滚,需要及时通知用户操作失败,并给出相应的错误信息和建议。

结合重试机制与库存回滚策略,不仅可以提高成功处理的概率,还可以在真正的失败时,确保系统的数据一致性。但需要注意,这种策略在高并发的场景下需要确保高效的执行,避免不必要的延迟和系统压力。

5 mini-spring

5.1 讲一讲你怎么实现aop的

5.2 一级缓存怎么实现你的aop

5.3 为什么spring创建bean时需要三级缓存而不是二级,不是一级

确实,三级缓存设计的目的在于解决特定的问题,而这些问题在只有一级或二级缓存的情况下可能无法得到满足。让我们更深入地探讨为什么三级缓存和二级缓存不能融合,以及为什么两者都是必要的。

为什么需要三级缓存?

  1. singletonFactories(三级缓存) 的存在是为了防止属性注入过程中的循环依赖。这是一个工厂方法,可以返回原始对象的早期引用,而这个对象可能还没有完全初始化。这种方法允许Spring在A依赖B,而B又依赖A的情况下,获取到A的早期引用,以完成B的初始化。

  2. earlySingletonObjects(二级缓存) 存放已经实例化但还没有完成完整初始化的bean。这是一个中间步骤,确保其他bean可以引用它,即使它还没有被完全初始化。但这只是一个引用,不能用于创建新的bean实例。

  3. 使用三级缓存的一个重要原因是Spring的AOP和其他后处理机制。这些机制可能会在bean完全初始化之前,对其进行修改或包裹。所以,为了保证能够获取到正确的对象版本,而不仅仅是原始的、未经处理的bean实例,Spring引入了ObjectFactory来实现延迟解析,只有当真正需要时才会触发真正的bean创建。

为什么不能融合?

两者的主要区别在于其目的和内容:

  • 三级缓存(singletonFactories)中存储的是创建bean实例的工厂对象,它可以产生bean实例,尤其是代理实例,因为bean有多个扩展点,后面的扩展点可能会包装前面的旧代理,生成新的代理,这就需要三级缓存中存的工厂对象生成新代理对象
  • 二级缓存(earlySingletonObjects)中存储的是已经部分初始化的bean实例本身。

当我们尝试解决循环依赖问题时,我们首先从三级缓存中获取bean工厂,用它来创建一个早期版本的bean,并存储在二级缓存中。这样,当其他bean试图在其初始化过程中引用这个早期bean时,它可以从二级缓存中直接获取,而不需要再次创建。

如果我们尝试融合这两个缓存,就会失去分离"如何创建bean"(三级缓存)和"早期的bean引用"(二级缓存)的能力,这是解决循环依赖的关键。

综上所述,为了有效地处理循环依赖,并确保bean的创建和引用都是高效和正确的,Spring选择了使用三级缓存而不是仅仅融合为一个或两个缓存。

5.4 循环依赖的解决过程

你的描述确实准确地描述了循环依赖的解决过程,而且是在只涉及一级和二级缓存的情况下。但三级缓存的作用在特定情况下是必要的,特别是在涉及bean工厂对象(即ObjectFactory)时。

为了更加准确地理解三级缓存的角色,我们要考虑到bean的生命周期和AOP代理的创建。考虑以下情景:

  1. A开始被初始化,但在完成前,它被放入三级缓存,即singletonFactories,作为一个ObjectFactory
  2. 在A的初始化过程中,B开始被初始化。
  3. B需要A。但A还没有完全初始化。此时,B可以从singletonFactories(三级缓存)中获取到A的ObjectFactory,并通过这个工厂对象获得A的早期引用。
  4. 这个早期引用随后被放入二级缓存(earlySingletonObjects)。
  5. B完成其初始化,并被放入一级缓存。
  6. A接着完成其初始化,并被放入一级缓存。

这种情况经常发生在涉及Spring AOP时。例如,当A是一个需要被代理的bean(可能因为事务、安全等原因),其实际的bean实例会被一个代理包裹。在这种情况下,singletonFactories缓存中存放的ObjectFactory能够生产出正确的代理对象,而不仅仅是原始的bean实例。

所以,虽然在简单的循环依赖情况下,你可能只看到了一级和二级缓存的作用,但在涉及复杂的bean生命周期和AOP代理的场景下,三级缓存是必要的。

5.5 如果A不是一个代理对象,在早期直接放入二级缓存就可以了对吧

是的,你是对的。如果A不是一个代理对象或不需要经过其他复杂的生命周期处理,它的早期引用可以直接放入二级缓存(earlySingletonObjects)。但如果A需要被代理或有其他后处理操作,那么使用ObjectFactory(放在三级缓存singletonFactories中)是有用的,因为这个工厂能够在被触发时生产出正确的对象(例如代理对象)。

6 rpc

6.1 讲讲rpc框架的调用流程

7 算法题

7.1 写一个滑动窗口的限流器,每秒限流100次,返回true或者false就行(带测试用例)

答:我每一秒产生一个限流器,限流的大小是100,这样会产生最多1s的误差;同时使用ConcurrentHashMap保证并发安全

class LimitFlowObject{Integer flowNum;Timestamp timestamp;public final static Integer THRESHOLD_FLOW=100;// 存放限流窗口static ConcurrentHashMap<String, LimitFlowObject> mp=new ConcurrentHashMap<>();static boolean limitFlow(String user,String interfaceName){String key=user+":"+interfaceName;long curTimeStamp= System.currentTimeMillis();if(mp.containsKey(key)&&mp.get(key).timestamp.getTime()>curTimeStamp){LimitFlowObject limitFlowObject=mp.get(key);limitFlowObject.flowNum+=1;mp.put(key, limitFlowObject);}else{LimitFlowObject limitFlowObject=new LimitFlowObject();limitFlowObject.flowNum=1;limitFlowObject.timestamp=new Timestamp(curTimeStamp+1000);mp.put(key, limitFlowObject);}if(mp.get(key).flowNum>THRESHOLD_FLOW){return false;}return true;}public static void main(String[] args) {Thread t1=new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 50; i++) {boolean f=limitFlow("a","b");if(!f)System.out.println("ith call:"+i+", "+"res:"+f);}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}for (int i = 50; i < 153; i++) {boolean f=limitFlow("a","b");if(!f)System.out.println("ith call:"+i+", "+"res:"+f);}}});t1.start();}
}

7.2 gpt4的改进

首先,我看到了您试图实现一个基于滑动窗口的限流器。但这个实现有一些问题,这里列举一些问题和提议:

  1. 线程安全性: ConcurrentHashMap 本身是线程安全的,但当您执行 mp.containsKey(key)mp.get(key) 的操作时,之间存在的时间间隔可能导致数据不一致。可能的解决方案是使用 compute()computeIfAbsent() 方法。

  2. 滑动窗口的设计: 目前的实现并不是真正的滑动窗口,因为它只考虑了1秒内的请求数量。真正的滑动窗口会在窗口范围内滑动,可能需要更复杂的数据结构来实现。

  3. 时间戳的处理: 使用 Timestamp 是可以的,但直接使用 System.currentTimeMillis() 作为long类型可能会更直观一些。

  4. 流控计数: 当窗口过期后,你应该重置计数。

考虑上述问题和建议,我为您提供了一个简化的实现(基于滑动窗口的精确实现通常更为复杂):

import java.sql.Timestamp;
import java.util.concurrent.ConcurrentHashMap;class LimitFlowObject {Integer flowNum;long timestamp;public final static Integer THRESHOLD_FLOW = 100;static ConcurrentHashMap<String, LimitFlowObject> mp = new ConcurrentHashMap<>();static boolean limitFlow(String user, String interfaceName) {String key = user + ":" + interfaceName;long curTimeStamp = System.currentTimeMillis();return mp.compute(key, (k, limitFlowObject) -> {if (limitFlowObject == null || limitFlowObject.timestamp <= curTimeStamp) {limitFlowObject = new LimitFlowObject();limitFlowObject.flowNum = 1;limitFlowObject.timestamp = curTimeStamp + 1000;} else {limitFlowObject.flowNum++;}return limitFlowObject;}).flowNum <= THRESHOLD_FLOW;}public static void main(String[] args) {Thread t1 = new Thread(() -> {for (int i = 0; i < 50; i++) {boolean f = limitFlow("a", "b");if (!f)System.out.println("ith call:" + i + ", " + "res:" + f);}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}for (int i = 50; i < 153; i++) {boolean f = limitFlow("a", "b");if (!f)System.out.println("ith call:" + i + ", " + "res:" + f);}});t1.start();}
}

这个实现简化了一些逻辑,并确保了操作的原子性。但需要注意,这并不是滑动窗口的完整或最优实现,仅仅是一个起点。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/114685.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于FPGA的图像拉普拉斯变换实现,包括tb测试文件和MATLAB辅助验证

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a vivado2019.2 3.部分核心程序 timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 202…

前端面试题整理(1.0)

1.nextTick原理 Vue是异步执行Dom更新的&#xff0c;一旦观察到数据变化&#xff0c;Vue就会开启一个队列&#xff0c;然后把在同一个事件循环&#xff08;event loop&#xff09;当中观察到数据变化的Watcher推送到这个队列。如果这个Watcher被触发多次&#xff0c;智慧被推送…

【Java基础面试四十一】、说一说你对static关键字的理解

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;说一说你对static关键字…

postgresql 配置文件 与 修改配置如何启用

2.启用配置 postgresql显式地以表格的方式告诉我们哪些配置项需要重启数据库实例、哪些配置项仅需要重新加载配置文件即可无需重启服务 select name, context from pg_settings context 的值指示具体策略&#xff1a; internal: 编译期间的设置&#xff0c;只有重新编译才能生…

2525.根据规则将箱子分类/并查集/动态规划

2525. 根据规则将箱子分类 - 力扣&#xff08;LeetCode&#xff09; 给你四个整数 length &#xff0c;width &#xff0c;height 和 mass &#xff0c;分别表示一个箱子的三个维度和质量&#xff0c;请你返回一个表示箱子 类别 的字符串。 如果满足以下条件&#xff0c;那么…

typescript实现一个简单的区块链

TypeScript 是一种由 Microsoft 推出的开源编程语言&#xff0c;它是 JavaScript 的超集&#xff0c;允许程序员使用面向对象的方式编写代码&#xff0c;并提供类型检查和语法提示等优秀的开发体验。区块链技术是一种分布式的、可靠的、不可篡改的数据库技术&#xff0c;用于记…

《数据结构与算法之美》读书笔记1

Java的学习 方法参数多态&#xff08;向上和向下转型&#xff09; 向上转型&#xff1a; class Text{public static void main(String[] args) {Animals people1 new NiuMa();people1.eat1();//调用继承后公共部分的方法&#xff0c;没重写调用没重写的&#xff0c;重写了调…

基于Django与深度学习的股票预测系统 计算机竞赛

文章目录 0 前言1 课题背景2 实现效果3 Django框架4 数据整理5 模型准备和训练6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于Django与深度学习的股票预测系统 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff…

Ubuntu桌面环境的切换方法

你在找它吗&#xff1f; 国内麒麟、深度等系统虽然界面更炫&#xff0c;但——软件仓库与Ubuntu官方已不兼容。国内系统遇到稳定性问题&#xff0c;还是得拿Ubuntu做参照。今天本来介绍下这款Linux桌面。 为什么在 Ubuntu 上考虑 LXQt&#xff1f; 性能&#xff1a;LXQt设计为…

计算机网络-计算机网络体系结构-传输层

目录 一、UDP 二、TCP 特点 首部格式 连接管理 可靠传输 流量控制(点对点) 拥塞控制(全局) 三、拥塞控制算法 慢开始&拥塞避免 快重传&快恢复 功能一&#xff1a;提供进程与进程之间的逻辑通信 功能二&#xff1a;复用和分用 功能三&#xff1a;对收到的报…

摩尔信使MThings的协议转换(数据网关)功能

摩尔信使MThings可以作为现场总线&#xff08;RS485&#xff09;和以太网的数据中枢&#xff0c;并拥有强大的Modbus协议转换功能。 数据网关功能提供协议转换和数据汇聚功能&#xff0c;可实现多维度映射&#xff0c;包括&#xff1a;不同的通道(总线)类型、协议类型&#xff…

PHP yield

概念&#xff1a; Generator&#xff1a;带 yield的function yield&#xff1a;Generator或task的中断关键字&#xff0c;执行到yield时一次调度周期执行完即阻塞&#xff0c;并返回右侧表达式结果&#xff0c;等待下一次调度器运行next()或迭代遍历才会继续往下执行&#xff0…

Axure RP静态站点的发布与内网穿透结合实现远程访问本地原型页面

文章目录 前言1.在AxureRP中生成HTML文件2.配置IIS服务3.添加防火墙安全策略4.使用cpolar内网穿透实现公网访问4.1 登录cpolar web ui管理界面4.2 启动website隧道4.3 获取公网URL地址4.4. 公网远程访问内网web站点4.5 配置固定二级子域名公网访问内网web站点4.5.1创建一条固定…

python生成的报告中绘制了多张图,但最后都混合到一起了

问题来源&#xff1a; 用python生成的报告中&#xff0c;存在三张图&#xff0c;第一个张图是正常的&#xff0c; 后面的图都是不正常的&#xff0c;全都是多张图混合而成的&#xff0c;这是为什么呢&#xff1f; 三段代码均是下述调用方式 import matplotlib.pyplot as plt pl…

【Linux】操作系统的认识

操作系统 1. 冯诺依曼体系结构2. 操作系统 1. 冯诺依曼体系结构 冯诺依曼体系结构的介绍 冯.诺依曼结构消除了原始计算机体系中&#xff0c;只能依靠硬件控制程序的状况&#xff08;程序作为控制器的一部分&#xff0c;作为硬件存在&#xff09;&#xff0c;将程序编码存储在…

JUC并发编程笔记2

省流&#xff1a; 自己笔记&#xff0c;划走~~~~ 缓存更新策略

mybatis-plus自动填充

前言 这是我在这个网站整理的笔记&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 mybatis-plus自动填充 大家做设计数据表的时候&#xff0c;基本上都会有del_flag&#xff0c;create_time, update_time,这三个字段&#xff0c;这也是…

【Java】迭代器的next方法

Collection 集合的遍历 概述&#xff1a;Iteration&#xff1a;迭代器&#xff0c;集合的专用遍历方式 Iterator<E> Iterator() 返回在此 collection 的元素上进行迭代的迭代器boolean hasNext() 如果返回仍有元素可以迭代&#xff0c;则返回 trueE next() 返回迭代的下一…

计算机视觉基础(5)——特征点及其描述子

前言 本文我们将学习到特征点及其描述子。在特征点检测中&#xff0c;我们将学习角点检测和SIFT关键点检测器&#xff0c;角点检测以哈里斯角点检测器为例进行说明&#xff0c;SIFT将从高斯拉普拉斯算子和高斯差分算子展开。在描述子部分&#xff0c;我们将分别学习SIFT描述子和…

【软考】软件开发中不同对象之间的关系

1. 关联&#xff08;Association&#xff09;&#xff1a; 关联表示两个或多个对象之间的关系。这种关系可以是双向的&#xff0c;也可以是单向的。关联关系通常用于描述两个对象之间的连接&#xff0c;但不涉及对象之间的所有权或整体-部分的关系。 例子&#xff1a; 考虑一…