C 中的异步读取

问题描述 投票:0回答:1

如何在 C 中使用

pread(2)
读取文件的一部分?我尝试过在
O_NONBLOCK
上使用
open()
标志,但读取似乎仍然阻塞线程(即一次读取很大一部分,1GB,似乎在我的 M1 mac 上将线程挂起大约 300 毫秒)

我已经研究过

aio_read()
但似乎在我的 Mac 上将
errno
设置为
EAGAIN
,无论我读了多少内容/磁盘有多忙

理想情况下,我想要一个解决方案,其中进程不必进行任何等待,并且可以简单地每毫秒轮询一次以检查缓冲区是否已填充,类似于nodejs的实现方式

fs.read(fd, ..., callback)

实现我想要的目标的正确方法是什么?我已经在网上搜索了几个小时,但大多数问题似乎都与套接字/管道有关,而不是实际文件(其中

read()
字面上等待新数据到达)

c disk aio
1个回答
0
投票

你说

如何在 C 中使用 pread(2) 读取文件的一部分?我尝试在 open() 上使用 O_NONBLOCK 标志,但读取似乎仍然阻塞线程(即一次读取很大一部分,1GB,似乎在我的 M1 mac 上将线程挂起大约 300 毫秒)

当然

O_NONBLOCK
在这里不是问题。内核不会因为它想要而阻止您的进程打开,而是因为它是必要的。使用非阻塞打开不会使读取继续进行,只是因为您说
O_NONBLOCK
。 (这意味着您进行的每个需要打开描述符的系统调用都会失败并出现错误
EAGAIN
,并且您将无法将数据写入任何地方)

顺便说一下,你的内核一次会从你的文件中提前读取 1Gb,这很奇怪。您的调用将始终阻塞(内核不会提供尽可能多的内存,如果您请求 1Gb,您的进程 -- 并且文件 inode 将被锁定 -- 将等待数据来自磁盘,直到它已将完整 GB 的数据传递给您的进程)虽然这对于套接字或管道来说不是这样,但对于文件来说却是这样。内核将文件读取实现为原子操作,以处理访问同一文件的其他线程/进程,并且该文件保持锁定状态(当 inode 被锁定时,没有其他系统调用可以在该文件上进行)如果您使用过

 read
write
而不是
pread
pwrite
结果应该是相同的(唯一的实现差异是操作中根本不使用文件指针,正如您在调用中提供的那样)

顺便说一句,从磁盘读取 1Gb 文件(因为相信我,该文件存储在磁盘中)仅需 300 毫秒,这是一个非常好的性能(平均为 3.5Gb/s),这可能是由于您想要读取的部分数据已经缓冲(因此没有使用磁盘访问)即使您有一个能够传输 40.0Gb/s 或更高速度的磁盘,也认为磁盘驱动程序必须花费一些时间来更换磁头(如果就是这种情况)并将您的请求与其他进程的请求混合。可能减慢数据访问速度的第二个因素是,如果您将进程放入仅计算(或 I/O)的任务,内核很快就会降低其优先级以有利于较短的 I/O 进程,并且此操作虽然高效对于更动态的过程,只会对您的过程产生负面影响。

© www.soinside.com 2019 - 2024. All rights reserved.