什么是时间片

典型回答 现在我们用到操作系统,无论是Windows、Linux还是MacOS等其实都是多用户多任务分时操作系统。使用这些操作系统的“用户”是可以“同时”干多件事的,这已经是日常习惯了,并没觉得有什么特别。 但是实际上,对于单CPU的计算机来说,在CPU中,同一时间是只能干一件事儿的。 **为了看起来像是“同时干多件事”,分时操作系统是把CPU的时间划分成长短基本相同的时间区间,即”时间片”。**通过操作系统的管理,把这些时间片依次轮流地分配给各个“用户”使用。 这样,给用户的感觉是他在同时的进行听歌和打游戏,实际上,在操作系统中,CPU是在游戏进程和音乐播放器进程之间来回切换执行的。 操作系统时间片的使用是有规则的:某个作业在时间片结束之前,整个任务还没有完成,那么该作业就被暂停下来,放弃CPU,等待下一轮循环再继续做。此时CPU又分配给另一个作业去使用。 我们把目光聚焦在CPU的执行上,把这个过程放大的话,CPU就好像是一个电话亭。多个用户并不是同一时间在使用这个电话亭中的电话的,而是轮流使用的。 不同的操作系统,在选择“用户”分配时间片的调度算法是不一样的,常用的有FCFS、轮转、SPN、SRT、HRRN、反馈等。 这个电话亭可以允许哪个用户进入打电话是有不同的策略的,不同的电话亭规定不同,有的电话亭采用排队机制(FCFS)、有的优先分配给打电话时间最短的人(SPN)等。 ✅能不能谈谈你对线程安全的理解?

March 22, 2026 · 1 min · santu

什么是MESI缓存一致性协议

典型回答 ✅什么是操作系统的多级缓存 由于CPU和主存的处理速度上存在一定差别,为了匹配这种差距,提升计算机能力,人们在CPU和主存之间增加了多层高速缓存。 每个CPU会有L1、L2甚至L3缓存,在多核计算机中会有多个CPU,那么就会存在多套缓存,那么这多套缓存之间的数据就可能出现不一致的现象。为了解决这个问题,有了内存模型。内存模型定义了共享内存系统中多线程程序读写操作行为的规范。通过这些规则来规范对内存的读写操作,从而保证指令执行的正确性。 但是引入了多级缓存之后,就会带来一个缓存一致性的问题。 首先,缓存一致性是由于引入缓存而导致的问题,所以,这是很多CPU厂商必须解决的问题。为了解决前面提到的缓存数据不一致的问题,人们提出过很多方案,通常来说有以下2种方案: 1、通过在总线加LOCK#锁的方式。 2、通过缓存一致性协议(Cache Coherence Protocol)。 在早期的CPU当中,是通过在总线上加LOCK#锁的形式来解决缓存不一致的问题。因为CPU和其他部件进行通信都是通过总线来进行的,如果对总线加LOCK#锁的话,也就是说阻塞了其他CPU对其他部件访问(如内存),从而使得只能有一个CPU能使用这个变量的内存。在总线上发出了LCOK#锁的信号,那么只有等待这段代码完全执行完毕之后,其他CPU才能从其内存读取变量,然后进行相应的操作。这样就解决了缓存不一致的问题。 但是由于在锁住总线期间,其他CPU无法访问内存,会导致效率低下。因此出现了第二种解决方案,通过缓存一致性协议来解决缓存一致性问题。 缓存一致性协议 缓存一致性协议(Cache Coherence Protocol),最出名的就是Intel 的MESI协议,MESI协议保证了每个缓存中使用的共享变量的副本是一致的。 MESI的核心的思想是:当CPU写数据时,如果发现操作的变量是共享变量,即在其他CPU中也存在该变量的副本,会发出信号通知其他CPU将该变量的缓存行置为无效状态,因此当其他CPU需要读取这个变量时,发现自己缓存中缓存该变量的缓存行是无效的,那么它就会从内存重新读取。 在MESI协议中,每个缓存可能有有4个状态,它们分别是: M(Modified):这行数据有效,数据被修改了,和内存中的数据不一致,数据只存在于本Cache中。 E(Exclusive):这行数据有效,数据和内存中的数据一致,数据只存在于本Cache中。 S(Shared):这行数据有效,数据和内存中的数据一致,数据存在于很多Cache中。 I(Invalid):这行数据无效。 有了这四种状态之后,MESI协议的工作流程如下: 当一个处理器需要读取一个缓存行时,它会首先检查该缓存行的状态。 如果状态是Exclusive或Shared,则直接从缓存中读取数据。因为这两种状态中数据都是有效的。 如果状态是Modified,则表明数据被修改了,则需要先将修改的数据写回主内存,然后再从主内存中读取数据。 如果状态是Invalid,则需要从主内存中加载数据到缓存,并设置状态为Exclusive或Shared。 当一个处理器修改了一个缓存行时,它会将状态设置为Modified,并通知其他处理器或核心该缓存行的状态已被修改,从而导致其他处理器中相应缓存行的状态变为Invalid。 通过这种方式,MESI协议确保了多个缓存中的数据一致性,避免了数据不一致导致的错误。它是一种常见的缓存一致性协议,被广泛应用于多核处理器和多处理器系统中。 扩展知识 MESI和JMM ✅有了MESI为啥还需要JMM?

March 22, 2026 · 1 min · santu

IO多路复用和多线程有什么区别?

典型回答 IO 多路复用和多线程是两种不同的技术,他们都是用于改善程序在处理多个任务或多个数据流时的效率和性能的。 但是他俩要解决的问题不一样!IO多路复用主要是提升I/O操作的效率和利用率,所以适合 IO 密集型应用。多线程则是提升CPU利用率的方法,所以适合 CPU 密集型应用。 IO 多路复用 在传统的阻塞式I/O模型中,应用程序在执行I/O操作(如读取网络数据)时,如果数据未准备好,线程会被阻塞,直到I/O操作完成。 IO多路复用技术通过允许单个线程同时监控多个I/O请求来解决这个问题。当使用select、poll或epoll等系统调用时,线程可以在不阻塞的情况下,检查多个I/O流的状态,只有当数据真正准备好时才处理它们。这样,即使在处理大量并发连接时,也能保持较低的线程数量,有效提高系统对I/O资源的利用率。 ✅如何理解select、poll、epoll? 由于主要使用单线程,相较于多线程,减少了线程创建和上下文切换的开销。 IO 多路复用适用于 I/O 密集型应用,特别是那些需要处理大量并发连接的服务器,如网络服务器。它使单个线程能够高效管理多个并发网络连接。 但IO 多路复用在处理多核 CPU 的并行计算上没有优势,且在处理长时间运行的计算任务时可能会造成 IO 等待。 多线程 多线程允许一个应用程序并发运行多个线程,每个线程可以独立执行任务。这允许程序同时执行多个操作,如同时处理多个用户请求。 利用多线程能够充分利用多核CPU的优势,适合CPU密集型应用。在处理需要长时间运算的任务时,可以显著提高效率和响应速度。 但是需要注意的是,线程间的上下文切换和资源共享可能导致性能开销。此外,多线程编程需要处理同步和并发控制的复杂性,如死锁和竞态条件。 如何选择 如果应用主要受限于 I/O,如 Web 服务器或文件服务,IO 多路复用可能更高效。 如果应用需要执行大量并行计算或利用多核 CPU,那么多线程可能是更好的选择。 在实际应用中,现代高性能服务器通常会结合使用这两种技术,通过 IO 多路复用来高效地管理 I/O,同时使用多线程来提升处理速度和并行计算能力,从而优化整体性能。

March 22, 2026 · 1 min · santu

为什么按位与运算要比取模运算高效?

典型回答 我们在HashMap 的 hash 算法相关文章,以及分库分表的数量选择文章中,都提到过,按位与运算要比取模运算更加高效。 ✅HashMap的hash方法是如何实现的? ✅分表数量为什么一般选择2的幂? 为什么呢? 首先,按位与运算(&)是计算机底层的基本操作,直接在二进制位上进行,由简单的逻辑门实现(AND 门),硬件电路非常简单,非常快速。他的时间复杂度是 O(1),处理每个位的操作在一个时钟周期内完成。 并且由于其简单性,编译器可以轻松地优化按位与运算。编译器在生成机器代码时,按位运算直接映射到单个机器指令。 而取模运算涉及除法操作,而除法操作比加法、减法和按位运算要复杂得多。因为在许多处理器架构中,除法运算通过迭代或流水线等复杂机制实现,导致其执行时间较长。虽然现代编译器对取模运算也进行了一定的优化,但由于其底层实现的复杂性,优化效果不如按位与运算明显。

March 22, 2026 · 1 min · santu

线程的实现方式有哪些?

我们都知道,在操作系统中,线程是比进程更轻量级的调度执行单位,线程的引入可以把一个进程的资源分配和执行调度分开,各个线程既可以共享进程资源,又可以独立调度。 其实,线程的实现方式主要有三种:分别是使用内核线程实现、使用用户线程实现以及使用用户线程加轻量级进程混合实现。 使用内核线程实现 内核线程(Kernel-Level Thread,KLT)就是直接由操作系统内核(Kernel)支持的线程,这种线程由内核来完成线程切换,内核通过操纵调度器(Scheduler)对线程进行调度,并负责将线程的任务映射到各个处理器上,并向应用程序提供API接口来管理线程。 应用程序一般不会直接去使用内核线程,而是去使用内核线程的一种高级接口——轻量级进程(Light Weight Process,LWP),轻量级进程就是我们通常意义上所讲的线程,由于每个轻量级进程都由一个内核线程支持,因此只有先支持内核线程,才能有轻量级进程。 有了内核线程的支持,每个轻量级进程都成为一个独立的调度单元,即使有一个轻量级进程在系统调用中阻塞了,也不会影响整个进程继续工作。 但是轻量级进程具有它的局限性:首先,由于是基于内核线程实现的,所以各种线程操作,如创建、析构及同步,都需要进行系统调用。而系统调用的代价相对较高,需要在用户态(User Mode)和内核态(Kernel Mode)中来回切换。其次,每个轻量级进程都需要有一个内核线程的支持,因此轻量级进程要消耗一定的内核资源(如内核线程的栈空间),因此一个系统支持轻量级进程的数量是有限的。 使用用户线程实现 在用户空间建立线程库,通过运行时系统(Run-time System)来完成线程的管理,因为这种线程的实现是在用户空间的,所以操作系统的内核并不知道线程的存在,所以内核管理的还是进程,所以这种线程的切换不需要内核操作。 这种实现方式下,进程和线程之间的关系是一对多的。 这种线程实现方式的优点是线程切换快,并且可以运行在任何操作系统之上,只需要实现线程库就行了。但是缺点也比较明显,就是所有线程的操作都需要用户程序自己处理,并且因为大多数系统调用都是阻塞的,所以一旦一个进程阻塞了,那么进程中的所有线程也会被阻塞。还有就是多处理器系统中如何将线程映射到其他处理器上也是一个比较大的问题。 使用用户线程加轻量级进程混合实现 还有一种混合实现的方式,就是线程的创建在用户空间完成,通过线程库进行,但是线程的调度是由内核来完成的。多个用户线程通过多路复用来复用多个内核线程。这个就不展开讲了。

March 22, 2026 · 1 min · santu

什么是 IO 密集,什么是 CPU 密集?

典型回答 “I/O 密集型”和“CPU 密集型”是用来描述程序在资源利用上的侧重点的。 对于I/O 密集型任务,顾名思义,他的资源利用上对 I/O操作更多一些。对于CPU 密集型任务,那么他的资源利用上对 CPU 的依赖就更多一些。 I/O 密集型 I/O 操作主要包含从磁盘读取数据、写入数据、网络传输、数据库操作等。I/O 密集型任务的瓶颈在于数据的输入和输出过程,而不是计算过程。 他的特点如下: 等待时间长:I/O 密集型任务通常涉及到大量的等待时间,等待磁盘、网络或其他外部设备的响应。 计算量小:这些任务通常需要的计算量相对较少,大部分时间花费在等待 I/O 操作的完成上。 适合多线程:由于 I/O 操作是非计算密集型的,多个线程可以在等待 I/O 操作完成的同时执行其他任务,从而提高整体效率。 常见的 I/O 密集型操作主要包括了文件的读写、网络请求、数据库查询等。 CPU 密集型 CPU 密集型任务涉及大量的计算操作,而不是 I/O 操作。这些任务的瓶颈在于计算能力和处理器的性能。 他的特点是: 计算量大:CPU 密集型任务需要进行大量的计算,例如复杂的数学运算、数据处理、图像处理等。 等待时间少:这些任务通常不会有长时间的等待时间,主要消耗 CPU 的计算资源。 适合多进程:可以利用多核处理器来并行计算,提升处理速度。 CPU 密集型,增加线程数没啥用了,因为CPU 已经很忙了,再有很多线程也忙不过来了,只能加 CPU 才有效果。 常见的CPU 密集型主要包括了图像处理、数据的计算、音视频编解码操作等会。

March 22, 2026 · 1 min · santu

给你一个文本文件,每一行包含一个 QQ号码,请用linux命令进行去重?

典型回答 想要在linux文件中移除重复的行,可以用sort -u命令: 1 sort -u filename.txt -o filename.txt sort:将文件的内容按字典顺序排序。 -u:表示去重(unique),会在排序后移除重复的行。 filename.txt:是包含 QQ 号码的文件名。 -o filename.txt:将去重后的内容直接写回到原文件。

March 22, 2026 · 1 min · santu

什么是“孤儿进程”,什么是“僵尸进程”?

典型回答 “孤儿进程”和“僵尸进程”是操作系统中两个常见的进程状态。 孤儿进程 所谓孤儿,就是无父无母了,那么孤儿进程指的就是一个进程的父进程没有了,即已经退出或者终止了,但是这个进程本身还在运行的情况。 在Unix/Linux系统中 。有一个init进程,进程号为1,如果一个进程变成了孤儿进程,那么操作系统会把他的父进程重新指定为init进程。(就像是孤儿院一样。) **举个栗子:**假设有一个进程A,它启动了进程B作为子进程。如果进程A结束了(无论是正常结束还是异常终止),那么进程B就成了孤儿进程。此时,操作系统会把进程B的父进程指向init进程。 僵尸进程 如果一个进程已经退出了,但是他还存在于进程表的话,那么这个进程就是僵尸进程。(虽然这些进程已经执行完毕,但它们的退出状态还没有被父进程回收。) 一个进程在结束后会向它的父进程发送一个退出信号(通常是SIGCHLD),并将退出状态保存下来。如果父进程没有及时处理这个退出信号,进程就会变成“僵尸进程”,即它已经不再执行任何任务,但它仍然占据着操作系统的某些资源(如进程号)。 举个栗子: 假设进程A启动了进程B,进程B完成了工作并退出。但如果进程A没有通过wait()获取进程B的退出状态,进程B就会变成僵尸进程。僵尸进程占用的是进程号和一些资源,但它不再消耗CPU。 注意,如果系统中有大量的僵尸进程,可能会导致资源的浪费,因为这些进程仍然占据着有限的进程号。

March 22, 2026 · 1 min · santu

常见的进程调度算法有哪些?

典型回答 在操作系统中,进程调度算法决定了 CPU 如何分配时间片给不同的进程。 ✅什么是时间片 常见的调度算法有以下几个: 先来先服务(FCFS, First Come First Served) 顾名思义,就是谁先来谁就有限获得CPU资源,类似排队买票,先来的进程先执行,后来的进程要等前面的执行完。 这个算法的优点就是公平,先来后到。缺点就是可能存在“长进程”影响后续进程,形成“短进程饥饿”现象。 短作业优先(SJF, Shortest Job First) 顾名思义,就短谁优先。分为非抢占式(进程一旦被选中,就会执行完)和抢占式(如果有更短的进程到来,会打断当前进程) 优点是可以最小化平均等待时间和周转时间(理论上最优)。缺点就是如何准确的预测谁的执行时间更短呢?另外就是长任务可能就一直拿不到时间片了。 优先级调度(Priority Scheduling) 为每个进程分配优先级,优先调度高优先级进程。同样分为抢占式和非抢占式。 优点就是如果某些任务真的很重要,可以给他加权,让他更快执行。缺点就是有些优先级低的进程可能就拿不到时间片了。 时间片轮转(RR, Round Robin) 这个简单,就是每个进程分配固定时间片(如 100ms),时间片用完则抢占并放入队列尾部,循环执行。 优点就是也挺公平的,大家顺序来,每个进程都能执行到,不会出现饥饿的情况,但是可能会导致CPU时间片的频繁切换。导致额外的消耗。 多级反馈队列(MLFQ, Multi-Level Feedback Queue) 进程根据执行时间和优先级被分配到不同队列,新进程进入最高优先级队列(时间片短),若进程用完时间片未结束,则降级到低优先级队列(时间片变长)。低优先级队列长时间未运行可升级优先级(防止饥饿)。 优点是可以兼顾短任务和长任务,提高系统响应速度。还能防止饥饿问题。唯一的缺点就是实现复杂度高,难以实现和优化。 完全公平调度(CFS, Completely Fair Scheduler) 基于虚拟运行时间(vruntime)分配 CPU,确保所有进程按权重公平获得执行时间。使用红黑树(Red-Black Tree)快速选择最小 vruntime 的进程。(现代 Linux 系统的默认调度器。) 优点是高公平性,低延迟,适合多任务混合负载。缺点是对实时任务支持需额外配置(如配合实时调度类)。 算法 抢占性 优点 缺点 适用场景 FCFS 非抢占 简单、公平 短进程饥饿 早期批处理系统 SJF/SRTF 非抢占/抢占 理论最优平均等待时间 依赖预知时间,长作业饥饿 已知时长的批处理任务 RR 抢占 公平,响应快 上下文切换开销 交互式系统(如分时 OS) 优先级调度 可选抢占 灵活定制优先级 低优先级进程饥饿 实时系统 多级反馈队列(MLFQ) 抢占 自适应,平衡长短作业 实现复杂 通用操作系统 CFS 抢占 高公平性,低延迟 实时任务需额外配置 现代 Linux 系统

March 22, 2026 · 1 min · santu

Linux下rm正在写入的文件会发生什么?

典型回答 在 Linux 中,文件的存储由两部分组成: 文件名(Directory Entry):用户看到的文件路径(如 /data/file.txt)。 文件数据(Inode 和数据块):实际存储文件内容的磁盘空间。 **rm**** 命令的作用是删除文件名与 inode 的链接(目录中看不到这个文件了)。如果该文件被其他进程正在写入,则 inode 和数据块不会立即释放,进程还可以继续写入(数据仍可写入),等所有进程关闭文件后再回收资源(回收文件的磁盘空间)。** 之所以这样,是因为其实在linux中,文件数据和文件名是分开的 文件名是目录中的一个“链接(link)”,指向 inode。 文件内容存在 inode 管理的 block 中。 rm 命令只是调用 unlink(),移除了一个目录项。

March 22, 2026 · 1 min · santu

留言给博主