初探 Reactor、Proactor 线程模型与 BIO、AIO、NIO

news2024/11/24 12:42:49

1 前言

工作中或者是技术上经常会遇到 I/O 、线程模型相关的问题,以及同步、异步、阻塞、非阻塞等各种基础问题,之前上学时候的概念认知总是模糊的,一知半解。趁这次了解希望能够更加深入的去了解这方面的知识,于是有了接下来这篇文章。

2 概念介绍

BIO/NIO/AIO 这些只是数据传输的输入输出流的一些形式而已。也就是说他们的本质就是输入输出流。只是存在同步异步,阻塞和非阻塞的问题。

reactor 和 proactor 呢,Reactors 和 Proactors 是两种用于处理并发网络请求的线程模型。它们主要用于高性能网络服务器和应用程序中,用以有效地管理多个同时发生的连接和请求。

总结来说,BIO、NIO和 AIO 是处理 I/O操作的不同方式,分别对应同步阻塞、同步非阻塞和异步非阻塞I/O。Reactor模型通常与NIO结合使用,而Proactor模型则与AIO结合使用,这样可以有效地处理高并发网络请求。这些模型的选择取决于应用程序的需求和特定的使用场景。

接下来也是文章会对他们一一进行大概的介绍。

3 操作 IO 的方式

首先说到这里,我们需要理解 IO 的原理。

无论是 Java 还是其他的语言,本质上 IO 读写操作的原理是类似的,编程语言开发的程序,一般都是工作在用户态空间,但由于 IO 读写对于计算机而言,属于高危操作,所以 OS 不可能 100% 将这些功能开放给用户态的程序使用,所以正常情况下的程序读写操作,本质上都是在调用 OS 内核提供的函数:read()、 write()。
也就是说,在程序中试图利用 IO 机制读写数据时,仅仅只是调用了内核提供的接口函数而已,本质上真正的 IO 操作还是由内核自己去完成的。

IO 的分类又有哪些呢
IO 以不同的维度划分,可以被分为多种类型,比如可以从工作层面划分成磁盘 IO(本地 IO)和网络 IO:

磁盘 IO:指计算机本地的输入输出,从本地读取一张图片、一段音频、一个视频载入内存,这都可以被称为是磁盘 IO。
网络 IO:指计算机网络层的输入输出,比如请求 / 响应、下载 / 上传等,都能够被称为网络 IO。
也可以从工作模式上划分,例如常听的 BIO、NIO、AIO,还可以从工作性质上分为阻塞式 IO 与非阻塞式 IO,亦或从多线程角度也可被分为同步 IO 与异步 IO.

3.1 同步与异步、阻塞与非阻塞

阻塞 IO
先来看看阻塞 I/O,当用户程序执行 read ,线程会被阻塞,一直等到内核数据准备好,并把数据从内核缓冲区拷贝到应用程序的缓冲区中,当拷贝过程完成,read 才会返回。注意,阻塞等待的是「内核数据准备好」和「数据从内核态拷贝到用户态」这两个过程。过程如下图:
在这里插入图片描述
非阻塞 IO
来看看非阻塞 I/O,非阻塞的 read 请求在数据未准备好的情况下立即返回,可以继续往下执行,此时应用程序不断轮询内核,直到数据准备好,内核将数据拷贝到应用程序缓冲区,read 调用才可以获取到结果。过程如下图:
在这里插入图片描述
注意,这里最后一次 read 调用,获取数据的过程,是一个同步的过程,是需要等待的过程。这里的同步指的是内核态的数据拷贝到用户程序的缓存区这个过程。只是非阻塞说不会去等待数据准备好的这个过程。在中间线程可以去干别的事,对于数据的拷贝以及返回还是同步的。

异步
因此,无论 read 和 send 是阻塞 I/O,还是非阻塞 I/O 都是同步调用。因为在 read 调用时,内核将数据从内核空间拷贝到用户空间的过程都是需要等待的,也就是说这个过程是同步的,如果内核实现的拷贝效率不高,read 调用就会在这个同步过程中等待比较长的时间。

而真正的异步 I/O 是「内核数据准备好」和「数据从内核态拷贝到用户态」这两个过程都不用等待。当我们发起 aio_read (异步 I/O) 之后,就立即返回,内核自动将数据从内核空间拷贝到用户空间,这个拷贝过程同样是异步的,内核自动完成的,和前面的同步操作不一样,应用程序并不需要主动发起拷贝动作。过程如下图:
在这里插入图片描述

很明显,异步 I/O 比同步 I/O 性能更好,因为异步 I/O 在「内核数据准备好」和「数据从内核空间拷贝到用户空间」这两个过程都不用等待。

这里顺便说个题外话什么是零拷贝

3.2 零拷贝

零拷贝(Zero-Copy)是一种在计算机系统中高效传输数据的技术,尤其在网络和文件系统操作中非常重要。它的核心目标是减少数据在系统内部传输过程中的拷贝次数,从而提高效率和减少延迟。零拷贝并不意味着没有任何数据拷贝发生,而是减少了在用户空间和内核空间之间的数据拷贝。

在理解零拷贝之前,我们先看看传统的数据传输过程:

在传统的数据传输(特别是在网络传输和文件读写中)中,数据通常会经历多次拷贝:
.

从磁盘到内核空间:首先,数据从磁盘读取到内核空间的缓冲区。
从内核空间到用户空间:然后,数据被拷贝到用户空间的应用程序缓冲区。
再次从用户空间到内核空间:当数据需要发送到网络时,它再次被拷贝回内核空间的网络缓冲区。
最后从内核空间到网络接口:最后,数据从内核空间发送到网络接口。
这种传统方法中,数据在用户空间和内核空间之间多次来回拷贝,造成了不必要的CPU负载和内存带宽消耗。

零拷贝

零拷贝技术的目的是减少这种在用户空间和内核空间之间的拷贝次数。它通常通过以下方式实现:

内核缓冲区直接传输:数据可以直接从内核缓冲区传输到网络,无需拷贝到用户空间。
内存映射(Memory-mapped files):应用程序可以通过映射文件到内存的方式直接在用户空间访问文件数据,减少拷贝次数。
sendfile 系统调用:这是一种特殊的系统调用,它可以直接在内核空间将文件数据发送到网络,无需先拷贝到用户空间。

其中什么是内存映射呢?

内存映射文件
内存映射文件通过将文件内容映射到进程的地址空间来改变这个过程:
文件映射到内存:操作系统创建一个文件内容的映射在进程的地址空间。这个映射区域的内存地址直接对应于文件数据在磁盘上的物理位置。
.
直接访问文件数据:应用程序可以直接在映射的内存区域中读写数据,就像访问普通的内存数组一样。这样做的时候,操作系统会确保这些操作反映到底层的文件上。
.
无需用户空间和内核空间之间的拷贝:因为应用程序直接在映射的内存区域操作数据,所以不需要将数据从内核空间拷贝到用户空间。

零拷贝与同步/异步IO
零拷贝技术与同步/异步IO的关系主要体现在它如何与这些IO模型结合以提高效率:

同步IO(阻塞/非阻塞):即使是在同步IO中,使用零拷贝可以减少CPU的使用和上下文切换,提高数据处理速度。
异步IO:异步IO的本质是减少IO操作对应用程序执行流的阻塞。结合零拷贝,它可以进一步提高效率,特别是在处理大量数据时。
总之,零拷贝是一种减少数据在不同内存区域(用户空间和内核空间)之间拷贝次数的技术,从而提高数据处理效率,减少CPU负担。它与同步或异步IO的特性结合使用,可以在多种场景下提高系统性能。

其实讲述了上面的这些案例和场景,再理解下面的 BIO、NIO、AIO 就比较简单了,那我们就简单的过一下。

3.3 BIO

BIO(Blocking-IO)

原理: BIO,即阻塞式I/O,是最传统的I/O模型。在BIO中,当一个线程执行I/O操作时(如读写文件、网络通信),线程会被阻塞,直到I/O操作完成。如果I/O操作延迟,线程就会在此期间一直等待,无法执行其他任务。

底层原理: BIO通常通过系统调用实现,这意味着当一个应用程序执行I/O操作时,它会调用操作系统的功能,然后等待操作系统返回结果。在这个过程中,线程处于阻塞状态。

应用场景: 简单的客户端应用或小规模的网络应用,其中并发量不高。

3.4 NIO

NIO(Non-Blocking-IO)

原理: NIO,即非阻塞式I/O,是一种允许线程在等待I/O操作完成时继续执行其他任务的模型。在NIO中,线程可以发起多个I/O请求,然后继续执行,不会停留在任何一个请求上等待其完成。

底层原理:

  • 选择器(Selector):NIO 的核心组件,允许单个线程管理多个 I/O 通道(Channel)。选择器会不断轮询注册在其上的通道,检查它们的 I/O 状态(如可读、可写)。
  • 缓冲区(Buffer):NIO 中数据的处理都是通过缓冲区进行的。每个操作都是围绕缓冲区进行的。
  • 通道(Channel):通道是双向的,可以用于读、写或同时进行读写操作,不像传统的流只能单向传输(输入或输出)。

应用场景: 高性能的服务器应用,如网络服务器和数据库服务器,其中需要处理大量并发连接。

其中 NIO(Non-blocking I/O)模型中的缓冲区(Buffer)和在讨论非阻塞I/O时提到的内核中的缓冲区是两个不同的概念。

NIO 中的缓冲区(Buffer)
.
定义: 在Java的NIO模型中,缓冲区是一块可以读写数据的内存区域。这个缓冲区存在于Java虚拟机(JVM)的内存中,而不是操作系统的内核空间。
作用: 缓冲区主要用于在非阻塞I/O操作过程中临时存储数据。当从一个通道(Channel)读取数据时,数据被读入到缓冲区;当往通道写数据时,数据从缓冲区写出。
类型: Java NIO 提供了多种类型的缓冲区,如 ByteBuffer, CharBuffer, IntBuffer 等,分别用于存储不同类型的数据。
控制: 缓冲区提供了对数据的细粒度控制,包括限制(limit)、位置(position)和容量(capacity)等属性,使得数据处理更加灵活。

非阻塞I/O中的内核缓冲区
.
定义: 非阻塞I/O中的内核缓冲区是操作系统内核空间中的一块内存区域,用于存储I/O操作的数据。
作用: 当进行网络或文件I/O操作时,数据会被存储在内核的缓冲区中,直到它们准备好被进程读取或已经被进程写入。
管理: 这些缓冲区完全由操作系统管理,应用程序无法直接访问或修改它们。应用程序通过系统调用与这些缓冲区交互。

总的来说,NIO 缓冲区是 Java NIO库中的一部分,由 Java 程序直接管理,主要用于 NIO 操作中的数据存储和传输。而非阻塞 I/O 中的内核缓冲区是操作系统管理的,用于在底层进行数据的存储和传输。这两者虽然都被称为“缓冲区”,但它们存在于不同的系统层次,并且由不同的实体管理。

3.5 AIO

AIO(Async-IO)
原理: AIO,即异步I/O,是一种不需要线程参与I/O操作等待的模型。在AIO模型中,应用程序可以直接发起一个I/O操作,并立即返回继续执行其他任务。当I/O操作完成后,操作系统会通知应用程序,或者启动一个回调函数处理结果。

底层原理:

  • 异步通道和完成处理器: AIO通过异步通道来执行I/O操作,当操作完成时,通过完成处理器(Completion Handler)或者Future对象来通知应用程序。
  • 操作系统支持: AIO需要操作系统底层支持异步I/O操作。在Linux系统中,这通常是通过IOCP(I/O Completion Port)等机制实现的。

应用场景: 适用于高并发和大规模网络应用,特别是那些I/O延迟较高的应用,如长时间等待响应的网络服务。

3.6 IO 上的区别

阻塞与否:BIO是阻塞的,NIO是非阻塞的,AIO是完全异步的。

线程使用:BIO需要为每个连接单独使用一个线程,而NIO可以使用单个线程管理多个连接,AIO则不需要线程持续等待I/O操作。

性能和适用场景:BIO适用于连接数较少且固定的应用场景,NIO适用于连接数较多但单个连接活动不是很高的场景,AIO适用于连接数多且连接非常活跃的高并发场景。
总的来说,这三种I/O模型各有优劣,

4 线程模型

4.1 Reactor 线程模型

Reactor 模型是一种事件驱动的架构模式,用于处理多个并发输入源的服务请求。这个模型主要用于实现高性能网络服务器。

工作原理

单一事件循环(Event Loop): Reactor 模式使用一个主循环,不断监听事件(如网络请求)。
事件多路分解器(Event Demultiplexer): 这个组件负责等待事件发生(例如,I/O操作完成、数据可读写等),并快速地将这些事件通知给相应的事件处理器。
事件处理器(Event Handlers): 每种类型的事件都有相应的事件处理器。当事件多路分解器捕获到事件时,它会调用对应的事件处理器进行处理。

这里我们使用小林哥文章里 [多 Reactor 多进程 / 线程] 的图概述一下。其中也有单 Reactor 单进程 / 线程的情况,后文会讲述到。
在这里插入图片描述
Reactor 单线程/进程 与 单 Reactor 多线程/多进程
这两种变体主要差异在于如何处理事件处理器的执行。

单 Reactor 单线程/进程:

原理: 所有的I/O处理(接收连接、读写数据)和请求处理都在同一个线程中完成。
优点: 简单,无需考虑多线程同步问题。
缺点: 一个线程处理所有任务可能成为性能瓶颈,特别是处理器密集型的任务。

单 Reactor 多线程/多进程:

原理: Reactor线程只负责I/O事件的监听和分发,真正的请求处理交给工作线程或进程来完成。
优点: 可以充分利用多核CPU,提高吞吐量,尤其适合于处理器密集型任务。
缺点: 复杂度高,需要处理线程间的同步和通信问题。

共同点与区别

  • 共同点:两者都采用事件驱动的方式处理请求,使用事件循环来监听和分发事件。
    区别:
  • 性能瓶颈:单线程模型的瓶颈在于无法同时处理多个请求或任务,而多线程模型的挑战在于线程管理和同步。
  • 适用场景:单线程模型适合轻量级和少量并发的场景,多线程模型更适合高并发、处理器密集型的场景。

总的来说,Reactor模型的选择(单线程还是多线程)取决于应用场景的具体需求,包括并发量、任务类型(I/O密集型还是CPU密集型)等因素。

应用与使用

网络服务器: Reactor 模型被广泛用于编写高性能网络服务器,如 HTTP 服务器、数据库服务器等。
框架和库: 许多流行的网络编程库和框架,如 Java 的 NIO 库、Node.js 的事件循环,都使用了Reactor模式。

目前的应用有哪些在用呢?

  • Web服务器: 如Apache、Nginx等。
  • 数据库: 如Redis。
  • 应用服务器: 例如Tomcat的NIO连接器。

4.2 Proactor 线程模型

其实上面已经讲到了很多同步与异步的区别。那么我们再说 proactor 模型。
Proactor 模型是一种异步处理并发输入源的服务请求的架构模式,常用于实现高性能网络服务器,特别是在需要处理大量并发I/O操作的场景中。

工作原理

异步操作发起: 在Proactor模型中,应用程序发起一个或多个异步I/O操作(如读取文件、网络数据传输)。
继续执行: 应用程序继续执行其他任务,而不是等待I/O操作完成。这样做可以充分利用CPU资源,避免了阻塞。
完成处理器(Completion Handler): 一旦异步I/O操作完成,系统会自动调用预设的完成处理器(或回调函数)来处理I/O操作的结果。
事件分发: 完成处理器处理异步I/O操作的结果,并可能根据需要触发其他操作或响应。

应用与使用

  • 网络编程: Proactor模式广泛用于网络编程中,尤其是在高性能服务器和客户端应用中,如大规模的Web应用、数据库系统等。
  • 框架和库: 一些现代编程语言和框架提供了对Proactor模式的支持,如Python的asyncio库。

4.3 区别与共同点

Q:既然多线程多进程的 reactor 线程模型最后能用线程池去处理这个问题,那跟异步处理的 proactor 线程模型的区别在什么地方呢?

A:

主要区别
I/O操作的同步性与异步性: Reactor模型中,即使使用多线程,I/O操作仍然是同步的;而在Proactor模型中,I/O操作是完全异步的。
线程阻塞: Reactor模型中,执行I/O操作的线程在操作完成前会阻塞;Proactor模型中,线程发起I/O操作后不会阻塞,I/O操作完成时通过回调进行通知。
处理器角色:Reactor模型中的处理器主要是分发事件;Proactor模型中的处理器是处理已完成的异步I/O操作。
.
总结
虽然多线程/多进程的Reactor模型通过线程池提高了并发处理能力,但它仍然依赖于同步I/O操作,适合于I/O操作较快的场景。而Proactor模型完全基于异步I/O,适合于I/O操作较多或较慢的高并发场景。选择哪种模型取决于应用程序的特定需求和I/O特性。

5 总结

所有这些模型和技术都旨在提高网络和I/O操作的效率。无论是通过同步还是异步方法,它们的目的都是最大限度地减少资源浪费,并提高应用程序处理并发请求的能力。

不同的处理方式

BIO (Blocking I/O): 适用于低负载、低并发的应用程序,易于理解和实现。
NIO (Non-blocking I/O): 适合高并发情况,通过单个线程管理多个连接,减少资源消耗。
AIO (Asynchronous I/O): 完全异步的方式处理I/O,适合I/O延迟较高的场景,如大量网络请求和大规模数据处理。

线程模型的进化

Reactor 模型: 基于事件驱动,高效管理多个连接。在NIO中得到了广泛应用。
Proactor 模型: 异步I/O的天然实现,通过异步操作和回调机制提高了程序的响应性和吞吐量。

技术选择的依据

选择这些技术的关键在于了解应用程序的需求:
对于简单的应用,BIO可能是一个简单直接的选择。
.
如果应用需要处理大量并发连接,但每个连接的实际活动不多,NIO或Reactor模型可能更合适。
.
对于需要处理大量异步I/O操作的高性能和高可伸缩性应用,AIO或Proactor模型可能是更好的选择。

在网络和 I/O 编程领域,没有一种通用的解决方案适用于所有情况。理解不同模型和技术的优势和局限性是关键。随着应用需求的不断变化,我们应该针对业务与需求选择合适的技术栈和架构模型。

6 引用

如何深刻理解Reactor和Proactor?
Java 中 BIO、NIO、AIO 有什么区别?
对线面试官:IO模型之BIO、NIO、AIO

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

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

相关文章

AWS 知识一:如何在AWS上启动云AD服务器(详细到极致)

前言: 首先这里指的云AD服务器,只是为了让读友更好理解。云AD服务器在AWS中称为目录。AWS一共提供了4种目录类别,下面我将全程使用AWS托管微软AD这种目录类别进行示例。他完全提供了和Microsoft AD的功能,包括NTLM,Ker…

Android-Binder基本原理

一、进程角度看IPC机制 在Android系统中,每个进程只能运行在自己所拥有的虚拟地址空间。例如,一个4GB的虚拟地址空间,包含3GB的用户空间和1GB的内核空间,内核空间的大小可以通过参数配置进行调整。两个进程之间的用户空间是彼此独…

如何开发一个免费的App

开发一个免费App意味着能够在项目启动初期,以更低成本的方式进行业务的迭代和市场化验证。 互联网发展到2023年,尤其在生成式AI及大模型技术“跃进式”增长的背景下,一个创新式商业模式的起步变得异常艰难。但如果用好工具,那么不…

【网络安全】—计算机网络基础

文章目录 网络必备基础物理层数据链路层与交换机网络模型OSI/TCP对等传输虚拟局域网VLAN静态路由与配置网络地址转换NAT访问控制列表ACLIP协议与IP地址分类子网掩码网关子网划分总结 计算机网络是指将地理位置不同的、功能独立的多台计算机通过通信线路连接起来,以功…

前端基础Vue项目中的插槽使用

概念 简单理解就是组件内部留一个或多个的插槽位置&#xff0c;可供组件传对应的模板代码进去。插槽的出现&#xff0c;让组件变的更加灵活。 1. 匿名插槽 父组件 <son><p>我是父组件通过匿名插槽传输的内容</p></son> 子组件 <template><di…

透过清澈的眼眸:新生儿视力检测的重要性与留意事项

引言&#xff1a; 新生儿的视力发展是其整体感知和认知能力的基础。因此&#xff0c;进行新生儿视力检测是保障他们健康成长的关键一步。本文将深入探讨新生儿视力检测的重要性&#xff0c;并提供父母在这一过程中需要留意的关键事项&#xff0c;以确保宝宝在视觉方面的正常发…

50ms时延工业相机

华睿工业相机A3504CG000 参数配置&#xff1a; 相机端到端理论时延&#xff1a;80ms 厂家同步信息&#xff0c;此款设备帧率上线23fps&#xff0c;单帧时延&#xff1a;43.48ms&#xff0c;按照一图缓存加上传输显示的话&#xff0c;厂家预估时延在&#xff1a;80ms 厂家还有…

2018年第七届数学建模国际赛小美赛C题共享单车对城市交通的影响解题全过程文档及程序

2018年第七届数学建模国际赛小美赛 C题 共享单车对城市交通的影响 原题再现&#xff1a; 共享自行车改变了许多城市的交通状况&#xff0c;许多大城市引入共享自行车来解决交通问题。我们需要定量评估共享自行车对城市交通的影响&#xff0c;以及相关的经济、社会和环境影响。…

人工智能辅助下的人工心脏:未来医疗的奇迹

导言 人工智能在医学领域的应用不断创新&#xff0c;其中人工心脏作为医疗工程的重要方向&#xff0c;将为心血管疾病患者带来新的治疗可能性。本文将深入研究人工智能辅助下的人工心脏技术&#xff0c;其原理、应用以及对未来医疗的影响&#xff0c;探讨人工心脏的发展历程、面…

七轴开源协作机械臂myArm视觉跟踪技术!

引言 ArUco标记是一种基于二维码的标记&#xff0c;可以被用于高效的场景识别和位置跟踪。这些标记的简单性和高效性使其成为机器视觉领域的理想选择&#xff0c;特别是在需要实时和高精度跟踪的场景中。结合机器学习和先进的图像处理技术&#xff0c;使用ArUco标记的机械臂系统…

安卓自动化 APP:轻松关闭任意开屏广告 | 开源日报 No.116

gkd-kit/gkd Stars: 8.7k License: GPL-3.0 基于无障碍 高级选择器 订阅规则的自定义屏幕点击 APP&#xff0c;主要功能包括实现跳过任意开屏广告、关闭应用内部弹窗广告以及一些快捷操作&#xff0c;如微信电脑登录自动同意和领取红包等。其核心优势和特点包括&#xff1a;…

[Ray Tracing in One Weekend] 笔记

前言 本文参照自raytracing in one weekend教程&#xff0c;地址为&#xff1a;https://raytracing.github.io/books/RayTracingInOneWeekend.html 什么是光线追踪&#xff1f; 光线追踪模拟现实中的成像原理&#xff0c;通过模拟一条条直线在场景内反射折射&#xff0c;最终…

【深度学习目标检测】十、基于yolov5的火灾烟雾识别(python,目标检测)

YOLOv5是目标检测领域一种非常优秀的模型&#xff0c;其具有以下几个优势&#xff1a; 1. 高精度&#xff1a;YOLOv5相比于其前身YOLOv4&#xff0c;在目标检测精度上有了显著的提升。YOLOv5使用了一系列的改进&#xff0c;如更深的网络结构、更多的特征层和更高分辨率的输入图…

失业无忧!掌握这四个网站,年收入10-20万!

大家好&#xff01;在职场中&#xff0c;失业可能是每个人都会面临的一种情况。当然&#xff0c;失业并不是终点&#xff0c;而是重新出发的起点。在这个充满机遇的数字时代&#xff0c;利用网络资源来提升自己是再合适不过了。今天&#xff0c;我将介绍四个非常有用的网站&…

patchless amsi学习(下)

patchless amsi 代码参考&#xff1a;https://gist.github.com/CCob/fe3b63d80890fafeca982f76c8a3efdf 解读代码可以从函数入口开始 setupAMSIBypass这个函数前面主要是获取amsiScanBuffer的地址&#xff0c;随即注册了一个veh异常。 然后通过调用GetThreadContext获取到了…

解决docker拉取镜像报错:Error response from daemon: Get “https://registry-1.docker.io/v2/“: dial tcp

1、问题&#xff1a;今天做完一个新项目&#xff0c;搭建了一个新的虚拟机&#xff0c;打算使用docker来搭建各种环境&#xff0c;发现拉取镜像报错 2、报错信息&#xff1a;Error response from daemon: Get "https://registry-1.docker.io/v2/": dial tcp 如下&am…

我从阿里云学到的返回值处理技巧

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 阿里云CosmoController…

【办公软件】C# NPOI 操作Excel 案例

文章目录 1、加入NPOI 程序集&#xff0c;使用nuget添加程序集2、引用NPOI程序集3、设置表格样式4、excel加载图片5、导出excel 1、加入NPOI 程序集&#xff0c;使用nuget添加程序集 2、引用NPOI程序集 private IWorkbook ExportExcel(PrintQuotationOrderViewModel model){//…

算法通关村第十关—快速排序(青铜)

快速排序 快排的基本过程 快速排序是将分治法运用到排序问题的典型例子  快速排序基本思想是&#xff1a;通过一个标记pivot元素将n个元素的序列划分为左右两个子序列left和right,.其中left中的元素都比pivot小&#xff0c;right的都比pivot的大&#xff0c;然后再次对Ieft和r…

企业办公加密系统中——全透明加密和半透明加密的区别

PC端访问地址&#xff1a; www.drhchina.com 天锐绿盾数据防泄密系统中的全透明加密和半透明加密的区别如下&#xff1a; 全透明加密是采用驱动层动态加解密技术&#xff0c;对企业内部所有涉密文档进行强制加密处理&#xff0c;从文件创建开始即可自动加密保护。加密文档在加…