为什么我们必须等待I / O?


28

众所周知,磁盘操作速度很慢,我们知道它们速度很慢的原因。所以这里的问题是为什么我们必须等待I / O或为什么会有IOWait之类的东西?

我的意思是我已经注意到,当您在后台执行一些I / O任务时,您的计算机基本上会变慢很多,我特别注意到,在使用Linux时,如果您要执行更长的I / O任务,直到操作系统完成,操作系统几乎变得无法使用。

确实,我也在文章中找到了这个主题,其中有一个摘要:

I / O等待率为12.1%。该服务器具有8个核心(通过cat / proc / cpuinfo)。这非常接近(1/8核心= 0.125)

所以从根本上讲,这意味着它会降低计算机的运行速度,为什么?我的意思是,好的,现在普通计算机至少有2个核心,有时是4个,有时是由于超线程等而拥有更多。但是现在的问题是,为什么CPU实际上必须呆在那里,除了等待IO之外,实际上不做其他任何事情?我的意思是流程管理的基本思想或体系结构,现在我不知道是操作系统负责还是将其归结为硬件部分,但应该让CPU等待或执行定期检查,同时实际执行许多其他任务,并且仅在准备就绪时返回IO流程。确实,如果这是一项艰巨的任务,而CPU必须等待,那为什么呢?这样可以更有效地利用硬件进行管理吗?例如,可能会有某种小型cpu会等待它,并在返回到流程后立即将一小部分数据传递到实际cpu,因此该流程将重复进行,而我们不必几乎将整个cpu核心专用于数据复制过程...还是我应该发明这种东西并为此获得诺贝尔奖?:S

现在,好了,我真的是从观察者的角度出发,我确实还没有深入探讨这个话题,但是我真的不明白为什么cpu必须以HDD的速度工作,尽管它可能只是做其他事情,一旦准备好就回到硬盘。这个想法不是要加快需要IO操作或复制过程或其他操作的应用程序的速度,而是要在执行该操作时将CPU占用的影响降到最低,以便OS可以将其用于其他进程和用户。进行某些复制操作时不必感到一般的计算机延迟...


41
“虽然它可以做其他事情”-例如?它需要处理数据。如果该数据不在CPU L1缓存中,则需要从L2缓存中获取数据。如果不在L2高速缓存中,则它需要从L3中获取(如果有的话)。如果根本不在缓存上,则需要访问主内存。如果不在主存储器中,则需要访问HDD。
Oded

39
计算机确实做别的事情; 内核会阻塞线程,直到IO操作完成为止,然后才能运行其他线程/进程。但是,如果一切都在磁盘IO上等待,那么就没有其他事情可做了。
上校32 22年

6
您必须等待程序到达I / O塔并将其飞盘发送给您!
Almo 2015年

1
@immibis正确!:)
Almo 2015年

2
通常,现代OS会执行您所抱怨的事情,而不是做您要抱怨的事情-IO操作被分派到适当的硬件,并且硬件会产生中断来表示操作已完成。等待IO的进程通常在等待时被阻塞(可以更改)。如果有许多进程在等待IO,并且没有其他进程可以让CPU做任何事情,那么就没什么可做的了。您也可能会陷入内存交换地狱。编写程序以有效利用CPU,内存和IO需要特殊技能,而其他正在运行的程序也会影响最有效的程序。
nategoose 2015年

Answers:


19

您描述的I / O方案当前在计算机中使用。

为什么CPU实际上必须停留在那儿,除了等待IO之外,实际上什么也没做?

这是一个最简单的I / O方式:可编程I / O。许多嵌入式系统和低端/低端微处理器只有一条输入指令和一条输出指令。处理器必须为每个读取或写入的字符执行明确的指令序列。

但应该让CPU等待或定期检查,同时实际执行许多其他任务,并且只有在准备就绪时才返回IO进程

许多个人计算机具有其他I / O方案。CPU 不必在紧要的循环中等待设备准备就绪(忙于等待),而是启动I / O设备,要求它在完成时生成中断(中断驱动的I / O)。

尽管由中断驱动的I / O向前迈了一大步(与已编程的I / O相比),但它需要为每个传输的字符中断,而且代价昂贵。

例如,可能会有某种小型cpu会等待它,并在返回到流程后立即将一小部分数据传递到实际cpu,因此该流程将重复进行,而我们不必实际上将整个cpu核心专用于数据复制过程...

解决许多问题的方法在于让别人来做!:-)

DMA控制器/芯片(直接内存访问)允许编程的I / O,但请其他人来做!

使用DMA,CPU只需初始化几个寄存器,就可以自由地做其他事情,直到传输完成(并引发中断)为止。

甚至DMA也不是完全免费的:高速设备可以将许多总线周期用于内存引用和设备引用(周期窃取),而CPU必须等待(DMA芯片始终具有更高的总线优先级)。

I / O等待率为12.1%。该服务器具有8个核心(通过cat / proc / cpuinfo)。这非常接近(1/8核心= 0.125)

我认为这来自: 了解磁盘I / O-您何时应该担心?

好吧,这并不奇怪:系统(mySQL)必须在操作数据之前获取所有行,并且没有其他活动。

这里没有计算机体系结构/操作系统问题。这就是示例的设置方式。

最多可能是RDBMS调整问题或SQL查询问题(缺少索引,错误的查询计划,错误的查询...)


24

可以编写异步IO,在此情况下,您告诉OS分派磁盘读/写操作,然后执行其他操作,然后再检查是否完成。它不是新事物。一种较旧的方法是将另一个线程用于IO。

但是,这要求您在执行读取操作时必须做一些事情,并且不允许您触摸传递给结果的缓冲区。

当您假设一切都阻塞IO时,编程也容易得多。

当您调用阻塞读取函数时,您会知道它不会返回,除非已读取某些内容,并且您可以立即对其进行处理。

典型的读取循环就是一个很好的例子

//variables that the loop uses
char[1024] buffer;
while((read = fread(buffer, 1024, 1, file))>0){
    //use buffer
}

否则,您需要保存当前函数状态(通常以回调+ userData指针的形式),并将其+读取操作的标识符传递回select()类型循环。如果操作完成,它将把读取操作的标识符映射到callback + data指针,并使用完成的操作信息调用回调。

void callback(void* buffer, int result, int fd, void* userData){
    if(result<=0){
    //done, free buffer and continue to normal processing
    }
    //use buffer

    int readID = async_read(fd, buffer, userData->buff_size);
    registerCallback(readId, callback, userData);
}

这也意味着,可能最终使用该异步读取的每个函数都需要能够处理异步继续。在大多数程序中,这都是不平凡的变化,您要求人们尝试进入异步C#。


但是,同步IO与异步IO并不是导致总体速度下降的原因。交换页面也是一项需要等待IO的操作。如果有一个调度程序,调度程序将只切换到另一个不在IO上等待的程序(IO等待是当处理器处于空闲状态并且有IO操作待处理时)。

真正的问题在于,硬盘驱动器和CPU都使用相同的通道与RAM进行通信。内存总线。而且,除非您使用RAID,否则只有一个磁盘可以从中获取数据。如果您还使用图形密集型应用程序,则情况将变得更糟,然后与GPU的通信也会受到干扰。

换句话说,真正的瓶颈可能在硬件而不是软件中。


6
“但是,同步IO与异步IO并不是导致总体速度下降的原因。” 那么,当问题是关于基础知识的时候,为什么您决定专注于这个相对高级的主题?
2015年

1
你或许应该提到一些关于DMA
亚历克·蒂尔

2
有趣的事实:实际上有一个非常古老的机制,它使程序在执行I / O时可以做其他事情而不必处理回调。这就是所谓的线程
user253751

2
很好地讨论了同步/异步IO的优缺点。但是,您确定那是造成经济放缓的原因吗?通常,我发现在IO负载过重的情况下,速度下降首先是由于软件体系结构欠佳,或者不是这种情况,这是因为系统使用的是单个慢速磁盘(即非SSD),并且所有人都试图同时访问它。我将磁盘服务请求的能力归咎于瓶颈,然后再将其归咎于内存总线的饱和。您需要真正的高端存储来使现代内存总线饱和。
aroth 2015年

9

确信在等待I / O时对其他内容的处理已相当简化,并且尽可能接近简化。当您发现计算机仅在12.1%的时间内等待I / O时,这意味着它实际上在并行执行许多其他操作。如果确实必须等待I / O而无需执行其他任何操作,则它将等待99.9%的时间,这就是I / O的速度。

并行执行更多操作的唯一方法是预测用户下一步可能想要做什么,而我们在这种预测方面还不是很擅长。因此,如果用户执行一项操作,要求从硬盘驱动器中读取特定的扇区,而该扇区尚未恰好位于高速缓存中,则操作系统将开始很长的读取该扇区的过程,会尝试同时查看是否还有其他事情要做。如果还有另一个用户想要一个不同的扇区,它也会将该请求排队。在某个时候,所有请求都已排队,我们无能为力,只能等待第一个请求得到满足,然后才能继续。这只是生活中的事实。

编辑:

寻找一个在执行I / O时如何做其他事情的解决方案将是一项令人钦佩的壮举,因为它同时也是在空闲时如何做其他事情的解决方案。这将是一个了不起的壮举,因为这意味着您将找到计算机可以做的工作,而计算机却没有任何工作。

您会发现,这就是发生的情况:您的计算机仅处于99.99%的时间中,什么也不做。当您给它做某事时,它就去做。如果这样做必须等待I / O,它就坐在那里等待。如果在执行I / O时还有其他事情要做,它也会这样做。 但是,如果除了I / O之外没有其他事情要做,那么它就必须坐在那里等待I / O完成。除了注册SETI @ Home,没有其他方法可以解决此问题。


那么12.1%的示例是从网站上获取的,该示例是从具有8个内核的服务器上获取的,当时的想法是几乎整个内核都只保留用于该操作,请确保其他内核可以自由地做任何事情并拥有8个内核您过得很好,但是如果只有一个核心,该怎么办?:/
Arturas M

3
@ArturasM您可能误解了网站的说法,或者网站的作者误解了。仅具有单个内核的计算机将花费更少的时间等待I / O(因为所有不等待IO的任务都在另一个内核上执行,而一个内核处于空闲状态,则所有任务都必须在单个内核上执行)核心)。无论您是否等待,I / O都会花费一定的时间-有时间等待它是与该时间无关的症状。
Random832

6

操作系统(除非是非常底层的嵌入式系统或类似的异国情调的东西)已经在处理此问题:如果您的应用程序必须等待I / O,则它通常会阻塞该I / O,并且其他线程或应用程序将变为活性。调度程序决定哪个。

只有在没有其他线程或应用程序正在运行的情况下,您才真正在等待时间。在引用的文章中(由于使用@manlio进行了链接),情况就是这样:您有12.1%的等待与87.4%的空闲,这意味着一个内核正在等待I / O完成,而其余的则什么都不做完全没有 给该系统做点事情,最好是多个事情,然后等待百分比应该下降。

当今应用程序设计的最高目标之一是确保即使只有一个应用程序正在运行,并且即使该单个应用程序在某个时刻正在等待I / O,该应用程序仍可以继续进行其他工作。线程是实现这种方法的一种方法,非阻塞I / O是另一种方法,但这在很大程度上取决于您正在执行的工作类型,实际上是否可以在没有等待数据的情况下完成某些工作。

当使用Linux时,如果您要执行更长的I / O任务,则在完成这些操作之前,该OS几乎变得无法使用。

这通常表示某些I / O绑定情况。我敢说系统不会变慢,因为它无法完成足够的CPU处理。这很可能是缓慢的,因为许多事情取决于当时很忙的HDD中的数据。这可能是您要运行的应用程序,但必须加载其可执行文件,库文件,图标,字体和其他资源。可能是您已经在运行的应用程序,但是它们已经交换了一部分内存,现在需要再次交换它们才能继续。它可能是某个守护程序,出于某种原因或其他原因,它认为它不仅必须在日志文件中写一行,而且实际上在响应某些请求之前先刷新该日志文件。

您可以使用类似于iotop查看I / O容量如何分配给进程以及ionice为进程设置I / O优先级的工具。例如,在台式机上,您可以将所有批量数据处理归类为idle调度类,以便某些交互式应用程序需要I / O带宽时,批量处理将暂停,直到完成交互式应用程序为止。


5

它确实取决于您的应用程序代码。我假设您的代码在Linux上运行。

您可以使用多线程(例如POSIX pthreads)来使受计算绑定的线程执行一些计算,而其他受IO绑定的线程正在执行IO(并等待它)。您甚至可以让您的应用程序运行与进程间通信(IPC)进行通信的多个 进程,请参见pipe(7)fifo(7)socket(7)unix(7)shm_overview(7)sem_overview(7)mmap(2)eventfd(2)并阅读Advanced Linux Programming等。

您可以使用非阻塞IO,例如传递O_NOBLOCKopen(2)等,等等。那么您将需要轮询(2)和/或使用SIGIO signal(7) ...并处理EWOULDBLOCK来自read(2)等的错误...

您可以使用POSIX异步IO,请参阅aio(7)

对于文件访问,您可以提示页面缓存,例如,在mmap(2)之后使用madvise (2)posix_fadvise(2);另请参见Linux特定的readahead(2)

但是您最终会遇到一些硬件瓶颈(总线,RAM等)。另请参见ionice(1)


1

我添加了其他观点,也许有争议:

它是Linux操作系统的典型问题。专门滞后(搜索“ Linux鼠标滞后”)。Windows没有此问题。我有双启动Windows 7和Linux Mint。即使在Windows中进行大量磁盘操作时,Windows也会发烟,鼠标仍在正常移动。相反,在Linux中,即使在正常的Web浏览过程中,感觉也不是那么动摇,有时鼠标也会滞后。

这可能是因为这两个系统的哲学和历史不同。Windows从一开始就是为普通用户设计的,其主要是图形操作系统。对于Windows用户而言,系统操作不流畅以及鼠标停止移动都表明存在问题。因此,Microsoft的程序员努力设计整个系统,以最大程度地减少系统运行缓慢的情况。在相反的Linux最初不是图形系统的情况下,台式机在这里只是第三者。Linux主要是为使用命令行的黑客设计的。把事情做好哲学。Linux根本不是为顺畅的行为而设计的,这里的感受并不重要。

注意:我并不是说Windows优于Linux,而是说它们只是具有不同的总体概念,在复杂的环境中,这可能导致这些系统具有不同的高级行为/感觉。


通过精心配置系统(例如niceionice在饥饿的进程中使用&),可以避免或减少Linux的鼠标滞后。而且我确实使用Linux,几乎从未经历过Linux鼠标滞后(除非计算机超载...)
Basile Starynkevitch 2015年

顺便说一句,Linux主要是服务器操作系统。
Basile Starynkevitch

我会注意到,即使在任务管理器和资源监视器显示内存使用率低,CPU和磁盘活动低的情况下,我在Windows 7上也遇到UI和鼠标滞后的情况。
8bittree
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.