Linux --- 高级IO

目录

1. 什么是IO

2. 阻塞的本质

3. 五种IO模型

3.1. 通过故事认识五种IO模型

3.2. 上述故事的总结

3.3. 具体的五种IO模型

3.3.1. 阻塞IO

3.3.2. 非阻塞轮询式IO

3.3.3. 信号驱动IO

3.3.4. 多路转接IO

3.3.5. 异步IO

4. 非阻塞IO

4.1. fcntl 系统调用


1. 什么是IO

冯诺依曼体系:

站在冯诺依曼体系的视角,从输入设备读取数据到存储器,这个过程就是Input;而将存储器的数据写入到输出设备,这个过程就是Output;

因此,IO本质上就是访问外设的过程。

因为外设相较于内存、cache缓存、寄存器、CPU的速率是比较低的,故IO的效率是比较低的,尤其涉及到网络,效率问题就更加突出。

2. 阻塞的本质

IO过程的低效,我们可以用读取数据为例:

当进程 read/recv 时,如果底层缓冲区没有数据,read/recv 会被阻塞;

当进程 read/recv 时,如果底层缓冲区有数据, read/recv 会将数据从内核缓冲区拷贝到应用层;

阻塞的本质:

  • 站在操作系统的视角: 将该进程的PCB放在等待队列中;
  • 站在进程自身的视角: 本质上就是让我这个进程等待;

因此,当进程等了 (等待事件就绪),数据就绪后,再进行数据拷贝,这就是一次IO过程;

故我们认为,IO = 等待 (事件就绪) + 数据拷贝

因此, read、recv、write、send 等,本质上都是先等待IO类事件就绪,在进行数据拷贝 (内核将数据拷贝给用户或者用户将数据拷贝给内核);

那么什么叫做低效的IO呢?

根据 IO = 等待 (事件就绪) + 数据拷贝,我们发现,单位时间,只要等待的比重越高,那么这个IO过程就越低效;

因此,那什么叫做高效的IO呢?即如何提高IO效率?

在单位时间,让等待的比重变得越低,那么IO的效率就变得越高,因此,高效IO的本质:降低IO过程中等待的比重,提高单位时间内拷贝数据的量;

3. 五种IO模型

3.1. 通过故事认识五种IO模型

通过一个钓鱼故事,来认识这五种IO模型:

今天,我们对钓鱼的过程进行简化一下(不要考虑什么打窝的事情了😄😄😄),我们认为钓鱼就分两步:

  • step 1: 等待鱼上钩, 等待事件就绪;
  • step 2: 鱼上钩后,把鱼钓起来, 数据拷贝。  

根据上面对IO的简单理解,类比到钓鱼过程中,什么情况下,一个人钓鱼的效率非常高呢?

  • 钓鱼 = 等待 + 钓起来;
  • 因此,只要单位时间等待的比重非常低,那么这个人钓鱼的效率一定非常高。

下面我们就通过一个故事,来认识下五种IO模型:

张三是一个钓鱼爱好者,带着帽子、墨镜、马扎,就来到鱼塘边,在钓鱼过程中:

张三死死的盯着鱼漂,其他事情都不做,鱼漂不动,他也不动,过了一会,鱼漂动了,张三就将鱼钓上来,这是张三;

李四是张三的老朋友,路过鱼塘时,看到张三在钓鱼,自己也拿着鱼竿去钓鱼了,在钓鱼过程中:

李四一会儿刷下手机,一会儿和张三聊天 ( 当然张三没理他 ),一会儿又盯着鱼漂,反正一直没闲着,过了一会儿,鱼漂动了,他抬头看了一眼,就将鱼钓了起来,这是李四;

王五也是一个钓鱼爱好者,路过鱼塘,也拿着鱼竿跑过来了,王五与前两者相比,多做了一步,他在鱼漂的位置挂了一个铃铛🔔,只要鱼漂一动,铃铛就会响,在钓鱼过程中:

王五一会儿看下张三、一会儿又和李四闲聊、一会儿又刷手机,在整个钓鱼过程中,反正王五就是不看鱼漂,过了一会儿,铃铛🔔响了,他头都不抬,直接收杆,将鱼钓起来了,这是王五;

赵六家是卖鱼竿的,路过鱼塘时,也想钓鱼,就从家里拿了100只鱼竿,将这些鱼竿全都用上,在钓鱼过程中:

因为挂了100只鱼竿,一会儿这边的鱼漂动了,一会儿那边的鱼漂动了,所以赵六就来回的跑,陆陆续续的鱼被钓上来了,这是赵六;

田七作为全村的首富,有一个司机叫小吴,这天,田七坐着豪华轿车路过鱼塘,看到鱼塘边的四个奇葩,一个一动不动,像个石头一样;一个像是多动症一样的;一个一直不看鱼漂;一个挂了密密麻麻的鱼竿,来回跑的汉子;

田七虽然不是非常想钓鱼,但是他却想吃鱼,因此对小吴说,咱去钓鱼,但是小吴说,不行,老板,你要去公司开会,不能钓鱼;田七想了想,行,这样,你帮我去钓鱼,我自己去公司,鱼钓上后,你给我打电话,我再过来;于是,小吴就去帮田七钓鱼去了,田七自己开车去公司开会了,这是田七;

3.2. 上述故事的总结

张三的钓鱼方式:阻塞式;

李四的钓鱼方式:非阻塞轮询式;

王五的钓鱼方式:信号驱动;

赵六的钓鱼方式:多路转接 (或多路复用);

田七的钓鱼方式:异步IO;

这五种方式,我们称之为五种IO模型;

谁钓鱼最高效呢?为什么?

赵六钓鱼是最高效的,因为:

  • 站在鱼🐟的角度,鱼🐟正在水里游哉悠哉的游着,抬头一看,看到104个食物 (诱饵) 在我的眼前,假设鱼🐟咬任何一个食物 (诱饵) 是等概率的,那么如果此时鱼🐟咬钩了,这个诱饵有 100/104,即25/26的概率是赵六的鱼饵;
  • 站在钓鱼者的角度,因为赵六的鱼竿很多,所以鱼🐟咬钩有很大概率咬的是赵六的鱼竿,所以赵六有很大概率钓上鱼,故在单位时间内,赵六等待的比重是非常低的,因此,赵六钓鱼的效率是非常高的。

只要一个执行流 (进程、线程) 参与了IO过程,我们就称之为同步IO;

IO的过程分两步:

  • 等待事件就绪;
  • 拷贝数据。

因此只要执行流参与了上述的任何一步、或者两者都参与了,那么我们就称之为同步IO;

故,在上面的五种IO模型中,前四种 (阻塞式、非阻塞轮询式、信号驱动、多路转接) 我们都称之为同步IO;

而对于最后一种,即田七的钓鱼方式而言,他既没有等待鱼🐟咬钩 (等待事件就绪),也没有钓起鱼🐟 (拷贝数据),故我们将这种IO方式,称之为异步IO;

王五的信号驱动算同步IO吗?

  • 首先,王五的信号驱动是同步IO, 可是,我们知道,信号的产生是异步的,这如何解释呢?
  • 因为IO = 等待事件就绪 + 拷贝数据, 虽然王五在等待过程中,可以做其他事情,但是一旦鱼咬钩了,王五是会将其钓上来的,换言之,当底层缓冲区有数据后,王五会进行数据拷贝,即王五是会参与IO过程的,故信号驱动这种方式也属于同步IO;
  • 虽然信号产生的确是异步的,但是当信号产生之后,信号驱动是要参与IO过程的,故信号驱动属于同步IO;
  • 换言之,我们认为,只要一个执行流参与了IO过程 (等待事件就绪 + 拷贝数据),我们就认为它是一个同步IO;
  • 如果一个执行流在整个IO过程都没有参与,完全脱离,那么就是异步IO;

阻塞IO和非阻塞轮询式IO,它们的区别是什么呢?

首先,阻塞IO和非阻塞轮询式IO都属于同步IO,因为它们都要参与IO过程 (等待数据就绪 + 拷贝数据);

其次,阻塞IO和非阻塞轮询式IO的主要区别就在于:等待数据就绪,这个等的比重不一样罢了,前者阻塞等待,后者非阻塞等待;

我们是学习过系统知识的,IO是谁在IO呢? 当然是执行流在IO;

因此,阻塞式IO,我们可以理解为执行流去检测某个文件描述符上是否有事件就绪,如果没有就绪,执行流就阻塞等待,等待事件就绪;

那什么是阻塞呢?

  • 站在操作系统的视角,就是把该执行流的PCB的状态由R -> !R状态,比如S状态,并将该PCB链入到某个等待队列中,这个队列一般都是与该执行流所等待的文件描述符相匹配的;
  • 此时这个执行流就被挂起阻塞了,后续就需要操作系统帮助处理了,比如操作系统识别到某个事件就绪,那么操作系统将在该文件描述符下等待的相关执行流唤醒,状态更改为R状态,并将PCB链入到运行队列中,此时这个执行流不就可以继续被调度,拷贝数据了吗?

多提一嘴,一般而言,执行流在等待什么,什么就需要提供相关队列,或者其他数据结构;

  • 比如,执行流等待某个条件变量,那么条件变量需要自身提供一个等待队列;
  • 再比如,执行流等待某个文件描述符,那么该文件描述符也需要提供一个等待队列。

那么什么是非阻塞呢?

  • 非阻塞,就是不阻塞啊,站在操作系统的视角,如果一个执行流检测某个文件描述符上的事件不就绪时,那么操作系统不会去更改这个执行流的状态,也不会将它的PCB链入到等待队列中,换言之,此时,操作系统并不关心,也不处理;
  • 因此,在非阻塞情况下,执行流不会被阻塞,故它可以在整个IO过程中不断的检测事件是否就绪,如果不就绪,可以处理其他任务,并稍后在进行检测,而这种模式不就是轮询过程吗?

不知道各位有这样的疑惑吗? 线程同步和同步IO这两个有关系吗?

  1. 先说答案, 毫无关系;
  2. 线程同步:在多线程场景下,多执行流协同工作时,为了解决访问临界资源合理性的问题,让执行流可以按照特定的顺序访问临界资源,我们称之为线程同步;
  3. 同步IO:一个执行流在进行IO时,如果参与了IO过程 (等待事件就绪或者拷贝数据),我们就认为它是同步IO;
  4. 线程同步是在多线程场景下,多执行流进行协同工作时,才会谈论的;
  5. 同步IO是在IO过程中,才会谈论的;
  6. 可见,线程同步和同步IO的应用场景都不相同,因此,这两者毫无关联。

3.3. 具体的五种IO模型

3.3.1. 阻塞IO

阻塞IO: 在内核将数据就绪之前,系统调用会一直等待 (阻塞等待),所有的文件描述符或者套接字,默认都是阻塞方式;

3.3.2. 非阻塞轮询式IO

非阻塞轮询式IO:如果内核还未将数据准备好,系统调用仍然会直接返回,并且返回 EWOULDBLOCK (Error Would Block)错误码;

非阻塞IO往往需要以循环的方式反复读写文件描述符,这个过程称之为轮询,非常消耗CPU的资源,一般只会在特定场景下使用。

3.3.3. 信号驱动IO

内核将数据准备好的时候,使用SIGIO信号通知执行流进行IO操作。 

从下图我们也可以看出,信号驱动这个等,并不是等待信号产生 (信号产生是异步的),而是等待数据,数据就绪后,内核会向执行流发送信号 (SIGIO),应用程序在拷贝数据; 

3.3.4. 多路转接IO

多路转接可以同时处理多个文件描述符,并且它只负责IO过程中的一个过程:等待事件就绪(数据拷贝它不关心,也不处理)。

  • 多路转接虽然也是阻塞等待,但是它与前面不同的是,它可以同时阻塞等待多个文件描述符,将多个文件描述符的等待时间重叠在一起,这些文件描述符可以在任意时刻就绪,只要其中一个文件描述符的事件就绪了,上层就可以处理这个文件描述符,此时上层绝不会被阻塞,因为此时这个事件已经就绪;
  • 通过多路转接,执行流可以将对多个文件描述符的IO操作集中在一起等待,当其中任何一个文件描述符上的IO事件就绪时,就会通知应用程序,从而避免了阻塞并提高了IO效率。

3.3.5. 异步IO

  • 可以看到,在整个IO过程中,这个应用程序没有参与其中,表现为,既没有等待数据就绪,也没有拷贝数据,因此,该执行流完全脱离IO过程,故它是异步IO;
  • 在整个IO过程中,等待数据就绪是内核完成的,将数据在内核和应用层拷贝也是操作系统进行的,数据拷贝完成后,通知应用程序;
  • 在整个IO过程中,应用程序可以在此期间处理其他任务。

4. 非阻塞IO

一个文件描述符或者套接字,默认情况下,都是阻塞式IO,而接下来,我们需要自己通过 fcntl 系统调用将特定文件描述符设定为非阻塞;

因此,我们先来见见 fcntl 系统调用吧 😊~~~~。

当然,也有其他的方法可以设置为非阻塞,比如,open 打开一个文件时,有一个选项,O_NONBLOCK 或者 O_NDELAY。

还比如, 创建一个套接字时,我们也可以设置选项,SOCK_NONBLOCK,设置为非阻塞;

但在后续处理过程中,对于文件描述符或者套接字,我们都会使用 fcntl 系统调用接口,以一种统一的方式来设置非阻塞; 

事实上,一个文件在读写数据时,阻塞和非阻塞无外乎就是文件的一个属性罢了;

4.1. fcntl 系统调用

fcntl() 是一个Linux系统调用,用于对文件描述符 (flie descriptor) 进行控制操作。

它的第二个参数 cmd 是一个整数,指定了要执行的操作类型,其余的参数取决于具体的操作类型。
函数原型如下:

man 2 fcntl --- 在2号手册
NAME
    fcntl --- manipulate file descriptor
SYNOPSIS
    #include <unistd.h>
    #include <fcntl.h>
    int fcntl(int fd, int cmd, ... /* arg */ );

RETURN VALUE
    on error, -1 is returned, and errno is set appropriately.
    For a successful call, the return value depends on the operation.

fcntl 根据传入的值不同, 其可变参数也不相同,在这列举几个,详细请看手册,或者文档:

  • F_SETFL:获取文件状态标志;
  • F_GETFL:设置文件状态标志;
  • F_DUPFD:复制文件描述符;
  • F_SETFD:设置文件描述符标志;
  • F_GETFD:获取文件描述符标志;
  • F_SETLK:设置文件锁;
  • F_GETLK:获取文件锁;

通过 fcntl() 系统调用将特定文件描述符设置为非阻塞的大致思路:

  1. 通过 cmd = F_GETFL 在底层获取当前文件描述符的文件状态标志,这个文件状态标志可以理解为一个位图;
  2. 通过 cmd = f_SETFL 设置当前文件描述符的文件状态标志,因为目的是非阻塞,故:文件状态标志 按位或 O_NONBLOCK,这里的文件状态标志就是步骤1获得的文件状态标志。

如下:

bool SetNonBlock(int fd)
{
  // 步骤一
  // 通过F_GETFL获取当前fd对应的文件状态标志
  // 可以将该文件状态标志(fl)理解为一个位图
  int fl = fcntl(fd, F_GETFL);
  if(fl == -1)
  {
    std::cout << "fcntl error" << std::endl;
    return false;
  }

  // 步骤二
  // 获取文件描述符的文件状态标志成功后
  // 将该文件描述符设置为非阻塞
  fcntl(fd, F_SETFL, fl | O_NONBLOCK);
  return true;
}

注意:

对于一个文件描述符而言,只需要通过 fcntl() 设置一次即可;

如果文件描述符设置为非阻塞,此时 read 时,我们需要通过返回值判定不同的处理方式,比如:

  • 如果返回值 > 0,代表读取成功;
  • 如果返回值 == -1,此时我们需要再次判断,是读取错误,还是底层数据没有就绪呢?

因此,我们需要通过 errno 这个全局变量,判别是读取错误,还是底层数据没有就绪, 比如:

  • 如果 errno == 11,即 errno == EWOULDBLOCK,那么代表着底层数据没有就绪,try again 即可;
  • 如果 errno == 4,即 errno == EINTR,代表着此次IO可能被某个信号中断,try again 即可;
  • 如果是其他错误码,进行差错处理。

简单实现一个,非阻塞轮询式IO,实现如下:

#include <iostream>
#include <cstring>
#include <unistd.h>
#include <fcntl.h>

bool SetNonBlock(int fd)
{
  // 步骤一
  // 通过F_GETFL获取当前fd对应的文件状态标志
  // 可以将该文件状态标志(fl)理解为一个位图
  int fl = fcntl(fd, F_GETFL);
  if(fl == -1)
  {
    std::cout << "fcntl error" << std::endl;
    return false;
  }

  // 步骤二
  // 获取文件描述符的文件状态标志成功后
  // 将该文件描述符设置为非阻塞
  fcntl(fd, F_SETFL, fl | O_NONBLOCK);
  return true;
}

int main()
{
  // 众所周知, 从0号文件描述符读取内容默认是以阻塞方式进行的
  // 但我们可以通过 fcntl 系统调用设置非阻塞IO
  if(!SetNonBlock(0)) exit(1);
  // 只需要设置一次即可
  // 后续的0号文件描述符就是非阻塞的
  
  char buffer[1024] = {0};
  while(true)
  {
    sleep(1);
    errno = 0;
    ssize_t real_size = read(0, buffer, sizeof buffer - 1);
    if(real_size > 0)
    {
      buffer[real_size] = 0;
      std::cout << "echo: " << buffer << "errno: " << errno << " errnoMessage: " << strerror(errno) << std::endl;
    }
    else
    {
      if(errno == EAGAIN || errno == EWOULDBLOCK)
      {
        // #define EWOULDBLOCK EAGAIN
        // #define EAGAIN 11
        // 当errno == 11时, 其实并没有错, 只不过底层数据没就绪, 再试一次吧~~~~
        std::cout << "Resource temporarily unavailable, Try again" << std::endl;
        continue;
      }
      else if(errno == EINTR)
      {
        // 此时也并不代表有错, 此次IO可能被某个信号中断了, Try again
        std::cout << "IO operation was interrupted by a signal, Try again" << std::endl;
        continue;
      }
      else
      {
        // 其他错误, 差错处理即可
        std::cout << "other error" << std::endl;
        exit(2);
      }
    }
  }
  return 0;
}

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

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

相关文章

麒麟信安LTF框架上线openEuler社区

麒麟信安LTF框架介绍 LTF&#xff08;Linux Test Framework&#xff09;是麒麟信安自动化组开发的一款面向Linux操作系统测试的自动化测试框架&#xff0c;目前已在openEuler社区开源。LTF工具积极投入国内各评测项目和日常版本测试任务中&#xff0c;汲取了在Linux自动化测试…

C语言预处理操作详解

这篇博客和大家分享一下C语言中的预处理操作。 1. 预定义符号 C语言设置了⼀些预定义符号&#xff0c;可以直接使用&#xff0c;预定义符号也是在预处理期间处理的。 __FILE__ //进行编译的源文件 __LINE__ //文件当前的行号 __DATA__ //文件被编译的日期 __TIME_…

【Android】重温Activity生命周期

前言 Android中用得最多的组件是Activity&#xff0c;而它的生命周期也是最基础的知识&#xff0c;从刚接触Android到工作中会频繁依赖这部分知识。可能大多数人能说出页面新建到页面关闭会走的生命周期&#xff1a;onCreate、onStart、onResume、onPause、onStop、onDestory&…

【五十三】【算法分析与设计】1392. 最长快乐前缀,686. 重复叠加字符串匹配,796. 旋转字符串,KMP算法

目录 1392. 最长快乐前缀 思路 过程 686. 重复叠加字符串匹配 796. 旋转字符串 string内置函数find KMP算法 结尾 1392. 最长快乐前缀 「快乐前缀」 是在原字符串中既是 非空 前缀也是后缀&#xff08;不包括原字符串自身&#xff09;的字符串。 给你一个字符串 s&…

JAVA_类和对象(1)

认识面向对象 Java是一门纯面向对象的语言(Object Oriented Program, OOP)&#xff0c;在面向对象的世界里&#xff0c;一切皆为对象。面向对象是解决问题的一种思想&#xff0c;主要依靠对象之间的交互完成一件事情。  面向过程和面相对象并不是一门语言&#xff0c;而是解决…

OpenStack镜像管理与制作

一、OpenStack镜像服务 1、什么是镜像 镜像通常是指一系列文件或一个磁盘驱动器的精确副本。虚拟机所使用的虚拟磁盘&#xff0c;实际上是一种特殊格式的镜像文件。云环境下尤其需要镜像。镜像就是一个模板&#xff0c;类似于VMware的虚拟机模板&#xff0c;其预先安装基本的…

格雷希尔G80L-T系列大口径快速连接器,在汽车膨胀水箱的气密性测试密封方案

副水箱也有人称作膨胀水箱&#xff0c;是汽车散热系统的一个重要组成部分&#xff0c;当水箱里面的温度过高的时候就会产生一定的压力&#xff0c;而副水箱可以根据热胀冷缩来帮助水箱和发动机排出去多余的水&#xff0c;起到一个调节的作用&#xff0c;副水箱由PP/PE塑料注塑而…

单向链表的实现

前言&#xff1a;继顺序表后的又一个线性结构——链表&#xff0c;这里将单向链表的实现。 目录 链表简介: 多文件实现&#xff1a; SList.h&#xff1a; SList.c实现函数的详解&#xff1a; 因为插入数据需要创建节点&#xff0c;很频繁&#xff0c;所以直接将创建新节点分…

《中医病证分类与代码》-中医疾病分类数据库

《中医病症分类与代码》由国家中医药管理局2020年底修订&#xff0c;目的是为中医疾病及证候的分类提供统一的规范。规定2021年起&#xff0c;各中医机构的临床科室及基层中医药的医师都应按照最新修订的《中医病症分类与代码》规范来填报病案及病历。 中医病证分类与代码数据库…

C++STL详解(一)— string类

string 类对象的常见容量操作 函数名称 功能 size 返回字符串有效字符长度length返回字符串有效字符长度capacity返回空间总大小clear清空有效字符empty检测字符串是否为空串&#xff0c;是返回true,否则返回falsereserve对容量进行改变resize扩容初始化 size和length 文档解…

Linux系统(centos,redhat,龙芯,麒麟等)忘记密码,怎么重置密码

Linux系统&#xff08;centos,redhat,龙芯&#xff0c;麒麟等&#xff09;忘记密码&#xff0c;怎么重置密码&#xff0c;怎么设置新的密码 今天在操作服务器时&#xff0c;DBA忘记了人大金仓数据库的kingbase密码&#xff0c;他的密码试了好多遍&#xff0c;都不行。最后只能…

sublime text中文---功能强大、操作便捷的代码编辑神器

Sublime Text是一款极受欢迎的代码编辑器&#xff0c;以其出色的性能、丰富的功能和优雅的用户界面赢得了广大开发者的青睐。它支持多种编程语言&#xff0c;包括HTML、CSS、JavaScript、Python等&#xff0c;让开发者能够轻松编辑和调试各种代码。Sublime Text拥有强大的自定义…

配置路由器实现互通

1.实验环境 实验用具包括两台路由器(或交换机)&#xff0c;一根双绞线缆&#xff0c;一台PC&#xff0c;一条Console 线缆。 2.需求描述 如图6.14 所示&#xff0c;将两台路由器的F0/0 接口相连&#xff0c;通过一台PC 连接设备的 Console 端口并配置P地址&#xff08;192.1…

SpringBoot是如何实现main方法启动Web项目的?

一、问题解析 在Spring Boot中&#xff0c;通过SpringApplication类的静态方法run来启动Web项目。当我们在main方法中调用run方法时&#xff0c;Spring Boot使用一个内嵌的Tomcat服务器&#xff0c;并将其配置为处理Web请求。 当应用程序启动时&#xff0c;Spring Boot会自动扫…

C#学习笔记11:winform上位机与西门子PLC网口通信_下篇

今日终于到了winform上位机与西门子PLC网口通信的系列收为阶段了&#xff0c;一直没一口气更新完&#xff0c;手头上也没有可以测试用的PLC设备&#xff0c;虚拟仿真用到的博图软件也不想下载&#xff08;会让我电脑变卡&#xff09;。 于是等了些日子购买西门子PLC&#xff0…

JIT在汽车行业中的革命性应用:颠覆传统制造模式,引领智能制造新时代

随着科技的飞速发展和市场竞争的日益激烈&#xff0c;汽车行业正面临着前所未有的变革。其中&#xff0c;准时制生产&#xff08;Just-In-Time&#xff0c;简称JIT&#xff09;作为一种先进的生产管理方式&#xff0c;已经在汽车行业中得到了广泛应用&#xff0c;成为推动汽车产…

密码学 | 椭圆曲线 ECC 密码学入门(三)

目录 7 这一切意味着什么&#xff1f; 8 椭圆曲线密码学的应用 9 椭圆曲线密码学的缺点 10 展望未来 ⚠️ 原文地址&#xff1a;A (Relatively Easy To Understand) Primer on Elliptic Curve Cryptography ⚠️ 写在前面&#xff1a;本文属搬运博客&#xff0c;自己留…

论文略读:Window Attention is Bugged: How not to Interpolate Position Embeddings

iclr 2024 reviewer 打分 6666 窗口注意力、位置嵌入以及高分辨率微调是现代Transformer X CV 时代的核心概念。论文发现&#xff0c;将这些几乎无处不在的组件简单地结合在一起&#xff0c;可能会对性能产生不利影响问题很简单&#xff1a;在使用窗口注意力时对位置嵌入进行插…

DC-1渗透测试复现

DC-1渗透测试复现 目的&#xff1a; 获取最高权限以及5个flag 过程&#xff1a; 信息打点-cms框架漏洞利用-数据库-登入admin-提权 环境&#xff1a; 攻击机&#xff1a;kali(192.168.85.136) 靶机&#xff1a;DC_1(192.168.85.131) 复现&#xff1a; 一.信息收集 扫…

IDEA 本地库引入了依赖但编译时找不到

在使用 IDEA 开发 Maven 项目的过程中&#xff0c;有时会遇到本地库引入了依赖&#xff0c;但编译时报找不到这个依赖&#xff0c;可以使用命令处理。 打开 Terminal。 执行清理命令。 mvn clean install -Dmaven.test.skiptrue执行更新命令。 mvn -U idea:idea