简体   繁体   English

异步 IO 中实际发生的情况

[英]What actually happens in asynchronous IO

I keep reading about why asynchronous IO is better than synchronous IO, which is because in a-sync IO, your program can keep running, while in sync IO you're blocked until operation is finished. I keep reading about why asynchronous IO is better than synchronous IO, which is because in a-sync IO, your program can keep running, while in sync IO you're blocked until operation is finished.
I do not understand this saying because using sync IO (such as write() ) the kernel writes the data to the disk - it doesn't happen by itself.我不明白这句话,因为使用同步 IO (例如write() ) kernel 将数据写入磁盘 - 它不会自行发生。 The kernel do need CPU time in order to do it. kernel 确实需要 CPU 时间才能完成。
So in a-sync IO, it needs it as well, which might result in context switch from my application to the kernel.所以在异步 IO 中,它也需要它,这可能会导致上下文从我的应用程序切换到 kernel。 So it's not really blocking, but there cpu cycles do need to run this operation.所以它并不是真正的阻塞,但确实需要 cpu 周期来运行这个操作。

  • Is that correct?那是对的吗?
  • Is the difference between those two that we assume disk access is slow, so compared to sync IO where you wait for the data to be written to disk, in a-sync IO the time you wait for it to be written to disk can be used to continue doing application processing, and the kernel part of writing it to disk is small?这两者之间的区别是我们假设磁盘访问很慢吗,所以与等待数据写入磁盘的同步 IO 相比,异步 IO 可以使用等待数据写入磁盘的时间继续做应用程序处理,kernel部分写入磁盘是小吗?
  • Let's say I have an application that all it does is get info and write it into files.假设我有一个应用程序,它所做的只是获取信息并将其写入文件。 Is there any benefit for using a-sync IO instead of sync IO?使用异步 IO 代替同步 IO 有什么好处吗?

Examples of sync IO:同步 IO 的示例:

  • write()写()

Examples of async IO:异步 IO 的示例:

  • io_uring (as I understand has zero copy as well, so it's a benefit) io_uring (据我所知也有零副本,所以这是一个好处)
  • spdk (should be best, though I don't understand how to use it) spdk(应该是最好的,虽然我不明白怎么用)
  • aio aio

The kernel do need CPU time in order to do it. kernel 确实需要 CPU 时间才能完成。

Is that correct?.那是对的吗?。

Pretty much, yes.差不多,是的。

Is the difference between those two that we assume disk access is slow... in a-sync IO the time you wait for it to be written to disk can be used to continue doing application processing, and the kernel part of writing it to disk is small?这两者之间的区别是我们假设磁盘访问很慢吗...在异步 IO 中,您等待将其写入磁盘的时间可用于继续进行应用程序处理,而 kernel 将其写入磁盘的部分是小?

Exactly.确切地。

Let's say I have an application that all it does is get info and write it into files.假设我有一个应用程序,它所做的只是获取信息并将其写入文件。 Is there any benefit for using a-sync IO instead of sync IO?使用异步 IO 代替同步 IO 有什么好处吗?

Depends on many factors.取决于许多因素。 How does the application "get info"?应用程序如何“获取信息”? Is it CPU intensive?它是 CPU 密集型的吗? Does it use the same IO as the writing?它使用与写作相同的 IO 吗? Is it a service that processes multiple requests concurrently?它是同时处理多个请求的服务吗? How many simultaneous connections?有多少同时连接? Is the performance important in the first place?首先,性能重要吗? In some cases: Yes, there may be significant benefit in using async IO.在某些情况下:是的,使用异步 IO 可能有很大的好处。 In some other cases, you may get most of the benefits by using sync IO in a separate thread.在其他一些情况下,您可以通过在单独的线程中使用同步 IO 来获得大部分好处。 And in other cases single threaded sync IO can be sufficient.在其他情况下,单线程同步 IO 就足够了。

Your understanding is partly right, but which tools you use are a matter of what programming model you prefer, and don't determine whether your program will freeze waiting for I/O operations to finish.您的理解部分正确,但是您使用哪些工具取决于您喜欢哪种编程 model,并且不要确定您的程序是否会冻结等待 I/O 操作完成。 For certain, specialized, very-high-load applications, some models are marginally to moderately more efficient, but unless you're in such a situation, you should pick the model that makes it easy to write and maintain your program and have it be portable to systems you and your users care about, not the one someone is marketing as high-performance.对于某些特定的、非常高负载的应用程序,某些模型的效率略高到中等,但除非您处于这种情况,否则您应该选择 model,它可以让您的程序易于编写和维护可移植到您和您的用户关心的系统,而不是有人将其营销为高性能的系统。

Traditionally, there were two ways to do I/O without blocking:传统上,有两种方法可以在不阻塞的情况下进行 I/O:

  1. Structure your program as an event loop performing select (nowadays poll ; select is outdated and has critical flaws) on a set of file descriptors that might be ready for reading input or accepting output.将您的程序构造为一个事件循环,在一组文件描述符上执行select (现在pollselect已过时并存在严重缺陷),这些文件描述符可能已准备好读取输入或接受 Z78E6221F6393D135668F。 This requires keeping some sort of explicit state for partial input that you're not ready to process yet and for pending output that you haven't been able to write out yet.这需要保留某种明确的 state 用于您尚未准备好处理的部分输入,以及您尚未能够写出的待处理 output。

  2. Separate I/O into separate execution contexts.将 I/O 分离到单独的执行上下文中。 Historically the unixy approach to this was separate processes, and that can still make sense when you have other reasons to want separate processes anyway (privilege isolation, etc.) but the more modern way to do this is with threads.从历史上看,统一的方法是单独的进程,当你有其他理由想要单独的进程(特权隔离等)时,这仍然是有意义的,但更现代的方法是使用线程。 With a separate execution context for each I/O channel you can just use normal blocking read / write (or even buffered stdio functions) and any partial input or unfinished output state is kept for you implicitly in the call frame stack/local variables of its execution context.使用每个 I/O 通道的单独执行上下文,您可以只使用正常的阻塞read / write (甚至缓冲的 stdio 函数)和任何部分输入或未完成的 output state隐式保存在其调用帧堆栈/局部变量中执行上下文。

Note that, of the above two options, only the latter helps with stalls from disk access being slow, as regular files are always "ready" for input and output according to select / poll .请注意,在上述两个选项中,只有后者有助于解决由于磁盘访问缓慢而导致的停顿,因为根据select / poll ,常规文件总是“准备好”输入和 output 。

Nowadays there's a trend, probably owing largely to languages like JavaScript, towards a third approach, the "async model", with even handler callbacks.现在有一种趋势,可能主要是由于像 JavaScript 这样的语言,朝着第三种方法,“异步模型”,甚至处理程序回调。 I find it harder to work with, requiring more boilerplate code, and harder to reason about, than either of the above methods, but plenty of people like it.我发现它比上述任何一种方法都更难使用,需要更多样板代码,也更难推理,但很多人喜欢它。 If you want to use it, it's probably preferable to do so with a library that abstracts the Linuxisms you mentioned (io_uring, etc.) so your program can run on other systems and doesn't depend on latest Linux fads.如果你想使用它,最好使用一个库来抽象你提到的 Linuxisms(io_uring 等),这样你的程序就可以在其他系统上运行并且不依赖于最新的 Linux 时尚。

Now to your particular question:现在到您的特定问题:

Let's say I have an application that all it does is get info and write it into files.假设我有一个应用程序,它所做的只是获取信息并将其写入文件。 Is there any benefit for using a-sync IO instead of sync IO?使用异步 IO 代替同步 IO 有什么好处吗?

If your application has a single input source (no interactivity) and single output, eg like most unix commands, there is absolutely no benefit to any kind of async I/O regardless of which programmind model (event loop, threads, async callbacks, whatever).如果您的应用程序具有单个输入源(无交互性)和单个 output,例如像大多数 unix 命令一样,那么无论哪个程序头脑 Z20F35E630DAF44DBs9回调,无论如何,任何类型的异步 I/O 都绝对没有好处( )。 The simplest and most efficient thing to do is just read and write.最简单、最有效的做法就是读写。

Context switching is necessary in any case.在任何情况下都需要上下文切换。 Kernel always works in its own context. Kernel 始终在其自己的上下文中工作。 So, the synchronous access doesn't save the processor time.因此,同步访问不会节省处理器时间。 Usually, writing doesn't require a lot of processor work.通常,编写不需要大量的处理器工作。 The limiting factor is the disk response.限制因素是磁盘响应。 The question is will we wait for this response do our work.问题是我们是否会等待这个回复来完成我们的工作。

Let's say I have an application that all it does is get info and write it into files.假设我有一个应用程序,它所做的只是获取信息并将其写入文件。 Is there any benefit for using a-sync IO instead of sync IO?使用异步 IO 代替同步 IO 有什么好处吗?

If you implement a synchronous access, your sequence is following:如果您实现同步访问,您的顺序如下:

  1. get information获取信息
  2. write information写信息
  3. goto 1.转到 1。

So, you can't get information until write() completes.因此,在 write() 完成之前,您无法获取信息。 Let the information supplier is as slow as the disk you write to.让信息提供者和你写入的磁盘一样慢。 In this case the program will be twice slower that the asynchronous one.在这种情况下,程序将比异步程序慢两倍。 If the information supplier can't wait and save the information while you are writing, you will lose portions of information when write.如果信息提供者在你写的时候等不及保存信息,你在写的时候会丢失部分信息。 Examples of such information sources could be sensors for quick processes.此类信息源的示例可能是用于快速处理的传感器。 In this case, you should synchronously read sensors and asynchronously save the obtained values.在这种情况下,您应该同步读取传感器并异步保存获得的值。

I do not understand this saying because using sync IO (such as write()) the kernel writes the data to the disk - it doesn't happen by itself.我不明白这句话,因为使用同步 IO(例如 write()) kernel 将数据写入磁盘 - 它不会自行发生。 The kernel do need CPU time in order to do it. kernel 确实需要 CPU 时间才能完成。

No. Most modern devices are able to transfer data to/from RAM by themselves (using DMA or bus mastering).不会。大多数现代设备都能够自己向 RAM 传输数据/从 RAM 传输数据(使用 DMA 或总线主控)。

For an example;举个例子; the CPU might tell a disk controller "read 4 sectors into RAM at address 0x12345000" and then the CPU can do anything else it likes while the disk controller does the transfer (and will be interrupted by an IRQ from the disk controller when the disk controller has finished transferring the data). the CPU might tell a disk controller "read 4 sectors into RAM at address 0x12345000" and then the CPU can do anything else it likes while the disk controller does the transfer (and will be interrupted by an IRQ from the disk controller when the disk controller已完成数据传输)。

However;然而; for modern systems (where you can have any number of processes all wanting to use the same device at the same time) the device driver has to maintain a list of pending operations.对于现代系统(您可以有任意数量的进程都想同时使用同一设备),设备驱动程序必须维护一个待处理操作的列表。 In this case (under load);在这种情况下(负载下); when the device generates an IRQ to say that it finished an operation the device driver responds by telling the device to start the next "pending operation".当设备生成一个 IRQ 表示它完成了一个操作时,设备驱动程序通过告诉设备开始下一个“挂起的操作”来响应。 That way the device spends almost no time idle waiting to be asked to start the next operation (much better device utilization) and the CPU spends almost all of its time doing something else (between IRQs).这样,设备几乎没有时间空闲等待被要求开始下一个操作(更好的设备利用率),而 CPU 几乎所有时间都在做其他事情(在 IRQ 之间)。

Of course often hardware is more advanced (eg having an internal queue of operations itself, so driver can tell it to do multiple things and it can start the next operation as soon as it finished the previous operation);当然,硬件通常更先进(例如,本身有一个内部操作队列,因此驱动程序可以告诉它做多件事,并且它可以在完成前一个操作后立即开始下一个操作); and often drivers are more advanced (eg having "IO priorities" to ensure that more important stuff is done first rather than just having a simple FIFO queue of pending operations).并且通常驱动程序更高级(例如,具有“IO 优先级”以确保首先完成更重要的事情,而不仅仅是拥有一个简单的等待操作的 FIFO 队列)。

Let's say I have an application that all it does is get info and write it into files.假设我有一个应用程序,它所做的只是获取信息并将其写入文件。 Is there any benefit for using a-sync IO instead of sync IO?使用异步 IO 代替同步 IO 有什么好处吗?

Lets say that you get info from deviceA (while CPU and deviceB are idle);假设您从 deviceA 获取信息(而 CPU 和 deviceB 空闲); then process that info a little (while deviceA and deviceB are idle);然后稍微处理该信息(当设备A和设备B空闲时); then write the result to deviceB (while deviceA and CPU are idle).然后将结果写入 deviceB(而 deviceA 和 CPU 空闲)。 You can see that most hardware is doing nothing most of the time (poor utilization).您可以看到大多数硬件大部分时间都没有做任何事情(利用率低下)。

With asynchronous IO;带异步IO; while deviceA is fetching the next piece of info the CPU can be processing the current piece of info while deviceB is writing the previous piece of info.当 deviceA 正在获取下一条信息时,CPU 可以处理当前信息,而 deviceB 正在写入前一条信息。 Under ideal conditions (no speed mismatches) you can achieve 100% utilization (deviceA, CPU and deviceB are never idle);在理想条件下(没有速度不匹配)可以达到 100% 的利用率(设备 A、CPU 和设备 B 永远不会空闲); and even if there are speed mismatches (eg deviceB needs to wait for CPU to finish processing the current piece) the time anything spends idle will be minimized (and utilization maximized as much as possible).并且即使存在速度不匹配(例如,设备B 需要等待CPU 完成当前部分的处理),任何花费空闲的时间都将被最小化(并且利用率尽可能地最大化)。

The other alternative is to use multiple tasks - eg one task that fetches data from deviceA synchronously and notifies another task when the data was read;另一种选择是使用多个任务——例如,一个任务从设备A同步获取数据,并在读取数据时通知另一个任务; a second task that waits until data arrives and processes it and notifies another task when the data was processed;第二个任务等待数据到达并处理它,并在处理数据时通知另一个任务; then a third task that waits until data was processed and writes it to deviceB synchronously.然后是第三个任务,等待直到数据被处理并将其同步写入设备B。 For utilization;供使用; this is effectively identical to using asynchronous IO (in fact it can be considered "emulation of asynchronous IO").这实际上与使用异步 IO 相同(实际上它可以被认为是“异步 IO 仿真”)。 The problem is that you've added a bunch of extra overhead managing and synchronizing multiple tasks (more RAM spent on state and stacks, task switches, lock contention, ...);问题是您添加了一堆额外的开销来管理和同步多个任务(更多的 RAM 花费在 state 和堆栈、任务切换、锁争用......); and made the code more complex and harder to maintain.并使代码更复杂,更难维护。

Asynchronous IO is not better than synchronous IO.异步 IO 并不比同步 IO 好。 Nor vice versa.反之亦然。

The question is which one is better for your use case.问题是哪一个更适合您的用例。

Synchronous IO is generally simpler to code, but asynchronous IO can lead to better throughput and responsiveness at the expense of more complicated code.同步 IO 通常更易于编码,但异步 IO 可以以更复杂的代码为代价获得更好的吞吐量和响应能力。

I never had any benefit from asynchronous IO just for file access, but some applications may benefit from it.我从来没有从异步 IO 中获得任何好处,只是用于文件访问,但某些应用程序可能会从中受益。

Applications accessing "slow" IO like the network or a terminal have the most benefit.访问“慢”IO(如网络或终端)的应用程序最受益。 Using asychronous IO allows them to do useful work while waiting for IO to complete.使用异步 IO 允许他们在等待 IO 完成时做有用的工作。 This can mean the ability to serve more clients or to keep the application responsive for the user.这可能意味着能够为更多的客户提供服务或保持应用程序对用户的响应。

(and "slow" just means that the time for an IO operation to finish is unbounded, it may ever never finish, eg when waiting for a user to press enter or a network client to send a command) (而“慢”只是意味着 IO 操作完成的时间是无限的,它可能永远不会完成,例如在等待用户按 Enter 或网络客户端发送命令时)

In the end, asynchronous IO doesn't do less work, it's just distributed differently in time to reduce idle waiting.最后,异步 IO 并没有做更少的工作,它只是在时间上分配不同,以减少空闲等待。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用模板时实际发生了什么? - What actually happens when you use templates? 在带有函数参数的C ++中实际发生了什么? - What actually happens in C++ with function parameters? 为实例变量(即对象)调用getter函数时,实际发生了什么? - What actually happens when calling a getter function for an instance variable(that is an object)? 在 C++ 中进行复制初始化时实际发生了什么? - What actually happens when copy initializing in C++? 当两个共享库定义相同的符号时,实际会发生什么? - What actually happens when two shared libraries define the same symbol? 实际发生在i,k; k&= i; - What actually happens int i, k; k &= i; 当检查 for 循环中的这种类型的条件时,实际会发生什么? - What actually happens when this type of condition in the for loop is checked? boost :: asio :: io_service :: run()实际做什么? - What does boost::asio::io_service::run() actually do? 关于铸造对象的地址空间的c风格类型转换期间实际发生了什么? - what actually happens during a c- style typecasting regarding address space of casted objects? C++ 当您从 function 返回结构时,汇编中实际发生了什么? - C++ What actually happens in assembly when you return a struct from a function?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM