高并发IO底层原理

1 概述

        IO底层原理是隐藏在Java编程知识之下的基础知识,是开发人员必须掌握的基本原理。本文从操作系统的底层原理入手,通过图文的方式为大家深入剖析高并发IO的底层原理,并介绍如何通过设置来让操作系统支持高并发。

2 IO读写的基本原理

        为了避免用户进程直接操作内核,保证内核安全,操作系统将内存(虚拟内存)分为两部分:内核空间(Kernel-space)和用户空间(User-space)。在Linux系统中,内核模块运行在内核空间,对应的进程处于内核态,用户程序运行在用户空间,对应的进程处于用户态。

        操作系统的核心是内核程序,它独立于普通的应用程序,既有权限访问收保护的内核空间,也有权限访问硬件设备,而普通的应用程序并没有这样的权限。内核空间总是驻留在内存中,是为操作系统的内核保留的。应用程序不允许直接在内核空间区域进行读写,也不允许直接调用内核代码定义的函数。每个应用程序进程都有一个单独的用户空间,对应的进行处于用户态,用户态进程不能访问内核空间的数据,也不能直接调用内核函数,因此需要将进程切换到内核态才能进行系统调用。

        内核态进程可以执行任意命令,调用系统的一切资源,而用户态进程只能执行简单的运算,不能直接调用系统资源,那么问题来了:用户进程如何执行系统调用呢?答案是:用户态进程必须通过系统调用(System Call)向内核发出指令,完成调用系统资源之类的操作。

        用户程序进行IO的读写依赖于底层的IO读写,基本上会用到底层的read和write两大系统调用。虽然在不同的操作系统中read和write两大系统调用的名称和形式可能不完全一样,但是它们的基本功能一样的。

        操作系统层面的read系统调用并不是直接从物理设备把数据读取到应用的内存中,write系统调用也不是直接把数据写入物理设备。上层应用无论是调用操作系统的read还是调用操作系统的write,都会涉及到缓冲区。具体来说,上层应用通过操作系统的read系统调用把数据从内核缓冲区复制到应用程序的进程缓冲区,通过操作系统的write调用把数据从应用程序的进程缓冲区复制到操作系统的内核缓冲区。

        简单来说,应用程序的IO操作实际上不是物理设备级别的读写,而是缓存的复制。read和write两个系统调用都不负责数据在内核缓冲区和物理设备之间的交换。这个底层的读写交换操作是由操作系统内核来完成的。所以,在应用程序中,无论是对socket的IO操作还是对文件的IO操作,都属于上层应用的开发,它们在输入和输出维度上的执行流程是类似的,都是在内核缓冲区和进程缓冲区之间进行数据交换。

2.1 内核缓冲区和进程缓冲区

        为什么设置那么多的缓冲区,导致读写过程那么麻烦?

        缓冲区的目的是减少与设备之间的频繁物理交换。计算机的外部物理设备与内存和CPU相比,有非常大的差距,外部设备的直接读写设计操作系统的中断。发生系统中断时,需要保存之间的进程数据和状态等信息,结束中断之后,还需要恢复之前的进程数据和状态等信息。为了减少底层系统的频繁中断所导致的时间损耗、性能损耗,出现了内核缓冲区。

        操作系统会对内核缓冲区进行监控,等待缓冲区到达一个数量的时候,再进行IO设备的中断处理,集中执行物理设备的实际IO操作,通过这种机制来提升系统的性能。至于具体什么执行系统中断则由操作系统的内核来决定,应用程序不需要关心。

        上层应用使用read调用时,仅仅把数据从内核缓冲区复制到应用的缓冲区(进程缓冲区);上层应用使用write调用时,仅仅把数据从应用的缓冲区复制到内核缓冲区。

        内核缓冲区与应用缓冲区在数量上也不同。在Linux系统中,操作系统内核只有一个内核缓冲区。每个用户程序(进程)都有自己独立的缓冲区,叫做用户缓冲区或者进程缓冲区。在大多数情况下,Linux系统中用户程序的IO读写程序并没有进行实际的IO操作,而是在用户缓冲区和内核缓冲区之间直接进行数据的交换。

2.2 典型的系统调用流程

        用户程序所使用的系统调用read和write并不是把数据在内核缓冲区和物理设备之间交换:read调用把数据从内核缓冲区复制到应用的用户缓冲区,write调用把数据从应用的用户缓冲区复制到内核缓冲区。两个系统调用的大致流程如下图:

b3fc6d6aeebf4babab1e08edfe2f15d6.jpeg

        这里以read系统调用为例,看一下一个完成输入流程的两个阶段:

        1、应用程序等待数据准备好。

        2、从内核缓冲区向用户缓冲区复制数据。

        如果是一个socket(套接字),那么以上两个阶段的具体处理流程如下:

        (1)第一个阶段,应用程序等待数据通过网路到达网卡,当所等待的分组到达时,数据被操作系统复制到内核缓冲区中。这个工作由操作系统自动完成,用户程序无感知。

        (2)第二个阶段,内核将数据从内核缓冲区复制到应用的用户缓冲区。

        再具体一点,如果是在Java客户端和服务器之间完成一个socket请求和响应(包括read和write)的数据交换,其完整的流程如下:

        1、客户端发送请求:Java客户端程序通过调用write系统调用将数据复制到内核缓冲区,Linux将内核缓冲区的请求数据通过客户端机器的网卡发送出去。在服务端,这份请求数据会从接收网卡中读取到服务器机器的内核缓冲区中。

        2、服务端获取请求:Java服务器程序通过read系统调用从Linux内核缓冲区读取数据,再送入Java进程缓冲区。

        3、服务端业务处理:Java服务器在自己的用户空间中完成客户端的请求所对应业务处理。

        4、服务端返回数据:Java服务器完成处理后,构建好的响应数据将从用户缓冲区写入内核缓冲区,这里用到的write系统调用,操作系统会负责将内核缓冲区的数据发送出去。

        5、发送给客户端:服务器Linux系统将内核缓冲区中的数据写入网卡,网卡通过底层的通信协议将数据发送给目标客户端。

3 四种主要的IO模型简介

        服务端高并发IO变成往往要求的性能都非常高,一般情况下需要所选用高性能的IO模型。另外,对于Java工程师来说,有关IO模型的知识也是通过的大公司面试必备要求。下面从最为基础的模型开始为大家揭秘IO模型的核心原理。常见的IO模型有四种。

3.1 同步阻塞IO

        首先,解释以下阻塞与非阻塞。阻塞IO指的是需要内核IO操作彻底完成后才返回到用户空间执行用户程序的操作指令。“阻塞”指的是用户程序(发起IO请求的进程或者线程)的执行状态。可以说传统的IO模型都是阻塞IO模型,并且在Java中默认创建的socket都属于阻塞IO模型。

        其次,解释一下同步与异步。简单来说,可以将同步与异步看成发起IO请求的两种方式。同步IO是指用户空间(进程或者线程)是主动发起IO请求的一方,系统内核是被动接收方。异步IO则相反,系统内核是主动发起IO请求,用户空间是被动接收方。

        同步阻塞IO(BIO)指的是用户空间(或者线程)主动发起,需要等待内核IO操作彻底完成后才返回到用户空间的IO操作。在IO操作过程中,发起IO请求的用户进程处于阻塞状态。

3.2 同步非阻塞IO

        非阻塞IO(NIO)指的是用户空间的程序不需要等待内核IO操作彻底完成,可以立即返回用户空间去执行后续的执行,即发起IO请求的用户进程处于非阻塞状态,与此同时,内核会立即返回给用户一个IO状态值。

        阻塞和非阻塞的区别是什么呢?阻塞是指用户进程一直在等待,而不能做别的事;非阻塞是指用户进程获得内核返回的状态值就返回自己的空间,可以去做别的事情。在Java中,非阻塞IO的socket被设置为NONBLOCK模式。

        【说明】同步非阻塞IO也可以简称为NIO,但它不是Java中的NIO。Java中的NIO(New IO)类库所归属的不是基础IO模型中的NIO,而是IO多路复用模型。

        同步非阻塞IO指的是用户进程主动发起,不需要等待内核IO模型彻底完成就能立即返回用户空间的IO操作。在IO操作过程中,发起IO请求的用户进行处于非阻塞状态。

3.3 IO多路复用

        为了提高性能,操作系统引入了一个新的系统调用,专门用户查询IO文件描述符(含socket连接)的就绪状态。在Linux系统中,新的系统调用为了select/epoll系统调用。通过该系统调用,一个用户进程可以监视多个文件描述符,一旦某个描述符就绪(一般是内核缓冲区可读/可写),内核就能将文件描述符的就绪状态返回给用户进程,用户空间可以根据文件描述符的就绪状态进行相应的IO系统调用。

        IO多路复用属于一种经典的Reactor模式实现,有时也称为异步阻塞IO,Java中的Selector属于这种模型。

3.4 异步IO

        异步IO(AIO)指的是用户空间的线程变成被动接收者,而内核空间成为主动调用者。在异步IO模型中,当用户线程收到通知时,数据已经被内核读取完毕并放在用户缓冲区中,内核在IO完成后通知用户线程直接使用即可。

        异步IO类似于Java中典型的回调模式,用户进程向内核空间注册了各种IO事件的回调函数,由内核主动调用。

        接下来对以上4种IO模型进行详细介绍。

4 四种IO模型详细介绍

4.1 同步阻塞IO

        模型情况下,在Java应用程序进程中所有对socket连接进行的IO操作都是同步阻塞IO。

        在阻塞IO模型中,从Java应用程序发起IO系统调用开始,一直到系统调用返回,这段时间内发起IO请求的Java进程是阻塞的。直到返回成功后,应用进程才能开始处理用户空间的缓冲区数据。同步阻塞IO的具体流程如下图:

2e1dff8c9a73419babed12d357a98d89.jpeg

        举个例子,在Java中发起一个socket的read操作的系统调用,大致流程如下:

        1、从Java进行IO读取后发起read系统调用开始,用户线程就进入阻塞状态。

        2、当系统内核收到read系统调用后就开始准备数据。一开始,数据可能还没到达内核缓冲区(例如,还没有收到一个完成的socket数据库),这时内核就要等待。

        3、内核一直等到完成的数据到达,就会将数据从内核缓冲区复制到用户缓冲区(用户空间的内存),然后内核返回结果(例如返回复制到用户缓冲区的字节数)。

        4、直到内核返回后用户线程才会接触阻塞的状态,重新运行起来。

        阻塞IO的特点是在内核指定IO操作的两个阶段,发起IO请求的用户进程被阻塞了。

        阻塞IO的优点是:应用程序开发非常简单;在阻塞等待数据期间,用户线程挂起,基本不会占用CPU资源。

        阻塞IO的缺点是:一般情况下会为每个连接配备一个独立的线程,一个线程维护一个连接的IO操作。在并发量下的情况下,这样做没什么问题。在高并发的应用场景下,阻塞IO模型需要大量的线程来维护大量的网路连接,内核、线程切换开销会非常巨大,性能很低,基本上是不可用的。

4.2 同步非阻塞IO

        在Linux系统下,socket连接默认是阻塞模式,可以将socket设置为非阻塞模式。在NIO模型中,应用程序一旦开始IO系统调用,就会出现以下两种情况:

        1、在内核缓冲区中没有数据的情况下,系统调用会立即返回一个调用失败的信息。

        2、在内核缓冲区中有数据的情况下,在数据的复制过程中系统调用时阻塞的,直到完成数据从内核缓冲区复制到用户缓冲区。复制完成后,系统调用返回成功,用户进程可以开始处理用户空间的缓冲区数据。同步非IO流程如下:

f0e931740d23417ca18a84985ed8ad6b.jpeg

        举个例子,发起一个非阻塞socket的read操作的系统调用,流程如下:

        1、在内核数据没有准备好的阶段,用户线程发起IO请求时立即返回。所以,为了读取最终的数据,用户进程需要不断的发起IO系统调用。

        2、在内核数据到达后,用户进程发起系统调用,用户进程阻塞。内核开始复制数据,它会将数据从内核缓冲区复制到用户缓冲区,然后内核返回结果(例如返回复制到用户缓冲区的字节数)。

        3、用户进程读到数据后,才会接触阻塞状态,重新运行起来。也就是说,用户空间需要经过多次尝试才能保证最终真正读到数据,然后继续执行。

        同步非阻塞IO的特点是应用程序的线程需要不断的进行IO系统调用,轮询数据是否已经准备好,如果没有准备好就继续轮询,直到完成IO系统调用为止。

        同步非阻塞IO的优点是每次发起的IO系统调用在内核等待数据过程中可以立即返回,用户线程不会阻塞,实时性较好。

        同步非阻塞IO的缺点是不断的轮询内核,将占用大量CPU的时间,效率低下。

        总体来说,在高并发场景中,同步非阻塞IO的性能很低,基本不可用,一般web服务器都不实用这种IO模型。在Java的实际开发中,不会涉及这种IO模型,但是此模型还是有价值的,其作用在于其他IO模型中可以使用非阻塞IO模型作为基础,是实现其高性能。

4.3 IO多路复用

        如何避免同步非阻塞IO模型中轮询等待的问题呢?答案是采用IO多路复用模型。

        目前支持IO多路复用的系统调用有select、epoll等。几乎所有的操作系统都支持select系统调用,它具有良好的跨平台特性。epoll是在Linux2.6内核中提出的,是select系统调用的Linux增强版本。

        在IO多路复用模型中通过select/epoll系统调用,单个应用程序的线程可以不断地轮询成百上千的socket连接的就绪状态,当某个或某些socket网路连接有IO就绪状态时就返回这些就绪的状态。

        举个例子来说明IO多路复用模型的流程。发起一个多路复用IO的read操作的系统调用,流程如下:

        1、选择器注册。首先,将需要read操作的目标文件描述符(socket连接)提前注册到Linux的select/epoll选择器中,在Java中所对应的选择器类是Slector类。然后,开启整个IO多路复用模型的轮询流程。

        2、就绪状态的轮询。通过选择器的查询方法,查询所有提前注册过的目标文件描述符(socket连接)的IO就绪状态。通过查询的系统调用,内核会返回一个就绪的socket列表。当任何一个注册过的socket中的数据准备好或者就绪了就说明内核缓冲区有数据了,内核将该socket加入就绪的列表中,并且返回就绪事件。

        3、用户线程获得了就绪状态的列表后,根据其中的socket连接发起read系统调用,用户线程阻塞。内核开始复制数据,将数据从内核缓冲区复制到用户缓冲区。

        4、复制完成后,内核返回结果,用户线程才会解除阻塞的状态,用户线程读取到了数据,继续执行。

        【说明】在用户进程进行IO就绪事件的轮询时,需要调用选择器的select查询方法,发起查询的用户进程或者线程是阻塞的。当然,如果使用了查询方法的非阻塞的重载版本,发起查询的用户进程也不会阻塞,重载版本会立即返回。

        IO多路复用模型的read系统调用流程如下图:

ce53700d4c4043f7949c4187b66a6fb6.jpeg

         IO多路复用模型的特点是:IO多路复用模型的IO涉及两种系统调用,一种是IO操作的系统调用,另一种是select/epoll就绪查询系统调用。IO多路复用模型建立在操作系统的基础设施之上,即操作系统的内核必须能够提供多路分离的系统调用select/epoll。

        和NIO模型相比,多路复用也需要轮询。负责select/epoll状态查询调用的线程,需要不断进行select/epoll轮询,以找出到达IO操作就绪的socket连接。

        IO多路复用模型与同步非阻塞IO模型是由密切关系的,具体来说,注册在选择器上的每一个可以查询的socket连接一般都设置成同步非阻塞模型,只是这一点对于用户程序而言是无感知的。

        IO多路复用模型的优点是一个选择器查询线程可以同时处理成千上万的网络连接,所以用户程序不必创建大量的线程,也不必维护这些线程,从而大大减少了系统的开销。与一个线程维护一个链连接的阻塞IO模式相比,这一点是IO多路复用模型的最大优势。

        通过JDK的源码可以看出,Java中的NIO组件在Linux系统上是使用epoll系统调用实现的。

        IO多路复用的缺点是,本质上select/epoll系统调用是阻塞式的,属于同步IO,需要在读写事件就绪后由系统调用本身负责读写,也就是说这个读写过程是阻塞的。要彻底解除线程的阻塞,就必须使用异步IO模型。

4.4 异步IO

        异步IO模型的基本流程是:用户线程通过系统调用向内核注册某个IO操作。内核在整个IO操作(包括数据准备、数据复制)完成后通知用户程序,用户执行后续的业务操作。

        在异步IO模型中,在整个内核的数据处理过程(包括内核将数据从网卡读取到内核缓冲区、将内核缓冲区的数据复制到用户缓冲区)中,用户程序都不需要阻塞。

        异步IO模型的流程如下图:

41ba819a1a954be5aca2694922a3d124.jpeg

        举个例子,发起一个异步IO的read操作的系统调用,流程如下:

        1、当用户线程发起read系统调用后,立刻就可以去做其他的事,用户线程不阻塞。

        2、内核开始IO的第一个阶段:准备数据。准备好数据,内核就会将数据从内核缓冲区复制到用户缓冲区。

        3、内核会给用户线程发送一个信号(Signal),或者回调用户线程注册的回调方法,告诉用户线程read系统调用已经完成,数据已经读入用户缓冲区。

        4、用户线程读取用户缓冲区的数据,完成后续的业务操作。

        异步IO模型的特点是在内核等待数据和复制数据的两个阶段,用户线程都不是阻塞的。用户线程需要接收内核的IO操作完成的事件,或者用户线程需要注册一个IO操作完成的回调函数。正因为如此,异步IO有的时候也称为信号驱动IO。

        异步IO模型的缺点是应用程序仅需要进行事件的注册与接收,其余的工作都留给了操作系统,也就是说需要底层内核提供支持。

        理论上来说,异步IO是真正的异步输入输出,它的吞吐量高于IO多路复用模型的吞吐量。就目前而言,Windows系统下通过IOCP实现了真正的异步IO。在Linux系统下,异步IO模型在2.6版本才引入,JDK对它的支持目前并不完善,因此异步IO在性能上没有明显的优势。

        大多数高并发服务端的程序都是基于Linux系统的。因而,目前这类高并发网路应用程序的开发大大采用IO多路复用模型。大名鼎鼎的Netty框架使用的是IO多路复用模型,而不是异步IO模型。

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

超声波清洗机真有用吗?眼镜党需注意!别被错误洗眼镜方法误导

超声波清洗机洗眼镜真的有用吗?眼镜党朋友一定要注意了,眼镜清洗可不能有一点马虎的哈! 眼镜是很多人日常生活中不可或缺的用品,然而清洁眼镜却是一个让人头疼的问题。随着科技的发展,超声波清洗机作为一种新兴的清洁…

pycharm Terminal命令行设置默认是Windows Powershell运行报错怎么修改?

目录 1. 真实案例 2. 如何做 3. 流程 3.1. 打开 settings 3.2. 在 最上方搜索 terminal 3.3. 在 shell path 里选择 cmd,并点击 OK 3.4. 重新打开 terminal 就成功了 1. 真实案例 使用 Windows Powershell 运行部分命令会不显示 2. 如何做 需要修改底部默认…

联系客服功能+定位功能+图片上传功能

功能一、联系客服 小程序开发的时候都会配备有类似于一个电话的悬浮按钮,比如: 这就是一个联系客服的功能,说白了就是打电话-----调用自己的电话功能进行拨打,具体代码实现 <!-- 点击拨打电话 --> makePhone: function (e) {var that this;var mobile e.currentTarget…

jmeter--常用插件及服务器监控(14)

一.jmeter插件管理器 下载jmeter插件管理器&#xff1a;plugins-manager.jar 下载plugins-manager.jar并将其放入lib/ext目录&#xff0c;然后重启JMeter。 插件管理界面 打开选项->Plugins Manager&#xff08;界面见下图&#xff09;&#xff0c;“Installed Plugns”…

discord音乐机器人

Discord音乐机器人是一种可以在Discord平台上使用的自动播放音乐的机器人。这些机器人可以连接到各种音乐源&#xff0c;如YouTube、SoundCloud和Spotify等&#xff0c;并根据用户的请求播放音乐。 Discord音乐机器人具有以下特点&#xff1a; 自动播放音乐&#xff1a;Disco…

友思特分享丨高精度彩色3D相机:开启崭新的彩色3D成像时代

来源&#xff1a;友思特 机器视觉与光电 友思特分享丨高精度彩色3D相机&#xff1a;开启崭新的彩色3D成像时代 原文链接&#xff1a;https://mp.weixin.qq.com/s/vPkfA5NizmiZmLiy_jv3Jg 欢迎关注虹科&#xff0c;为您提供最新资讯&#xff01; 3D成像的新时代 近年来&#…

flutter 文件下载及存储路径

flutter 文件下载及存储路径 前言一、下载进度条二、文件路径二、文件上传总结 前言 日常开发中&#xff0c;经常会遇到下载文件的功能&#xff0c;往往我们在需要保存文件的路径上去调试&#xff0c;比如Android中的路径&#xff0c;有些会报错在SD卡中&#xff0c;但是有些手…

11 双向链表

单链表的局限&#xff1a; 单链表的缺点&#xff1a;逆序访问单链表中的元素耗时大。&#xff08;时间复杂度&#xff1a;O&#xff09; 双向链表的定义 第0个节点【a1】的pre指针为NULL&#xff0c;要注意 插入操作&#xff1a; 删除操作&#xff1a; 初步实现双链表 代码&…

智能制造工业互联网建设方案——青创智通工业物联网

智能制造已经成为工业发展的重要趋势。智能制造系统架构与工业物联网建设方案作为实现智能制造的关键环节&#xff0c;对于推动工业转型升级和提升企业竞争力具有重要意义。青创智通工业物联网重点探讨智能制造系统架构与工业物联网建设方案的核心要素、实施步骤和未来发展方向…

vue-echarts踩坑,本地开发可以渲染echarts图表,线上环境图表渲染不出来

main.js全局注册v-chart组件 import VueECharts from "vue-echarts"; Vue.component("v-chart", VueECharts);在页面中使用 如上图&#xff0c;我开始写的静态数据&#xff0c;在data中定义了chartOption1:{…配置项…}, 在接口数据返回之后&#xff0c;…

AI能否真的取代程序员?

一个Java程序员从接到需求到最终开发完功能的流程大致如下 首先是理解原型图&#xff0c;设计表结构根据表结构编写增删改查代码与前端联调&#xff0c;完成功能开发 那么以上步骤AI能不能完成呢&#xff1f; 让我们试一下&#xff1a; 第一步&#xff0c;使用 AI助手 解析流…

【AI】无人零售和边缘计算

目录 一、什么是边缘计算 1.1 边缘计算的定义 1.2 边缘计算的作用 1.3 边缘计算的关键技术 1.4 边缘计算的应用场景 二、边缘计算在无人零售中的应用 一、什么是边缘计算 1.1 边缘计算的定义 边缘计算&#xff08;Edge Computing&#xff09;是一种分布式计算范式&#…

Android 事件机制探讨(1)

事件的传递主要有三个方法&#xff1a;dispatchTouchEvent(事件分发)、onInterceptTouchEvent(事件拦截)、onTouchEvent(事件消费)。如下图&#xff1a; 仔细看的话&#xff0c;图分为3层&#xff0c;从上往下依次是Activity、ViewGroup、View事件从左上角那个白色箭头开始&…

ssm基于WEB技术的在线商品交易平台的设计+vue论文

在线商品交易平台的设计与实现 摘要 近年来&#xff0c;信息化管理行业的不断兴起&#xff0c;使得人们的日常生活越来越离不开计算机和互联网技术。首先&#xff0c;根据收集到的用户需求分析&#xff0c;对设计系统有一个初步的认识与了解&#xff0c;确定在线商品交易平台的…

芯品荟 | 测亩仪市场调研报告

一、产品简介 1、什么是测亩仪&#xff1f; 测亩仪&#xff0c;又称面积测量仪&#xff0c;采用了卫星定位系统与高精度算法技术原理&#xff0c;可以精准测量出土地、水域的距离、周长、面积等数据的有效工具&#xff0c;被广泛应用于农田、林业、水域、公路、机械作业、野外…

OpenAIOps社区线上宣讲会圆满召开,期待您的加入!

2024年1月12日“OpenAIOps社区”线上宣讲会圆满召开&#xff0c;群体智慧协同创新社区的创立为AIOps领域未来发展注入了活力。OpenAIOps社区是一个AIOps开源社区及创新平台&#xff0c;由中国计算机学会(CCF)、清华大学、南开大学、中科院、国防科大、必示科技等单位共同发起&a…

智慧公厕:颠覆传统公共厕所管理的未来之路

公共卫生设施一直是城市管理中的重要环节&#xff0c;而智慧公厕作为一种全新的公用卫生设施&#xff0c;以其融合了物联网、大数据、云计算等新型信息技术的特点&#xff0c;引起了人们的广泛关注。通过智能化手段的管理和服务&#xff0c;智慧公厕不仅解决了传统公厕中存在的…

20240111在ubuntu20.04.6下解压缩RAR格式的压缩包

20240111在ubuntu20.04.6下解压缩RAR格式的压缩包 2024/1/11 18:25 百度搜搜&#xff1a;ubuntu rar文件怎么解压 rootrootrootroot-X99-Turbo:~/temp$ ll total 2916 drwx------ 3 rootroot rootroot 4096 1月 11 18:28 ./ drwxr-xr-x 25 rootroot rootroot 4096 1月…

C语言多线程基础(pthread)

1.线程和进程的概念 线程&#xff1a;进程中的一个实体&#xff0c;是CPU调度和分派的基本单位。可以与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤销另一个线程&#xff0c;同一进程中的多个线程之间可以并发执行&#xff0c;线程在运行中呈现间断…

MYSQL的事务隔离

本章概览 mysql是一个支持多引擎的系统&#xff0c;并不是所有引擎都支持事务&#xff0c;本篇以innodb为例解析mysql在事务支持的实现。提到事务一定会想到ACID(Atomicity、Consistency、Isolation、Durability&#xff0c;即原子性、一致性、隔离性、持久性)&#xff0c;今天…