考虑一个受CPU限制的应用程序,但也具有高性能I/O要求.
我正在将Linux文件I/O与Windows进行比较,我看不出epoll将如何帮助Linux程序.内核会告诉我文件描述符"准备好读取",但是我仍然需要调用阻塞read()来获取我的数据,如果我想读取兆字节,那么很明显它会阻塞.
在Windows上,我可以创建一个设置了OVERLAPPED的文件句柄,然后使用非阻塞I/O,并在I/O完成时收到通知,并使用该完成函数中的数据.我需要不花费应用程序级别的挂钟时间等待数据,这意味着我可以精确地将我的线程数调整为我的内核数量,并获得100%的高效CPU利用率.
如果我必须在Linux上模拟异步I/O,那么我必须分配一些线程来执行此操作,并且这些线程将花费一些时间来处理CPU事务,并且大量时间阻塞I/O,此外,在这些线程的消息传递中会有开销.因此,我将过度订阅或利用我的CPU核心.
我把mmap()+ madvise()(WILLNEED)视为"穷人的异步I/O",但它仍然没有完全通过那里,因为当它完成时我无法得到通知 - 我有"猜测",如果我猜"错误",我将最终阻止内存访问,等待数据来自磁盘.
Linux似乎在io_submit中启动了异步I/O,它似乎也有一个用户空间POSIX aio实现,但它已经有一段时间了,我知道没有人会担保这些系统的关键,高性能的应用程序.
Windows模型的工作方式大致如下:
步骤1/2通常作为单个事物完成.步骤3/4通常使用工作线程池完成,而不是(必要)与发出I/O相同的线程.这个模型有点类似于boost :: asio提供的模型,除了boost :: asio实际上不会给你异步的基于块的(磁盘)I/O.
Linux中epoll的不同之处在于,在步骤4中,还没有I/O发生 - 它会在步骤4之后提升第1步,如果你确切知道你需要的话,那就是"向后".
编写了大量的嵌入式,桌面和服务器操作系统之后,我可以说这种异步I/O模型对于某些类型的程序来说非常自然.它还具有非常高的吞吐量和低开销.我认为这是Linux I/O模型在API级别上仍然存在的真正缺点之一.
我有一个事件驱动的网络服务器程序.此程序接受来自其他主机上其他进程的连接.在同一远程IP上可能存在来自不同端口的许多短期连接.
目前,我有一个while(1)循环调用accept()然后生成一个线程来处理新连接.读取消息后,每个连接都将关闭.在远程端,在发送消息后关闭连接.
我想通过缓存打开的套接字FD来消除设置和拆除连接的开销.在发送方,这很容易 - 我只是不关闭连接,并保持它们.
在接收方,它有点难.我知道我可以存储accept()在结构中返回的FD 并使用poll()或监听所有这些套接字上的消息select(),但我想同时通过所有缓存连接监听新连接accept() 并监听.
如果我使用两个线程,一个打开poll(),一个打开accept(),那么当accept()调用返回(打开一个新连接)时,我必须唤醒另一个等待旧连接的线程.我知道我可以通过一个信号做到这一点pselect(),但是对于这么简单的事情来说,这整个混乱似乎太过分了.
有没有一个电话或更好的方法可以让我同时处理打开的新连接和旧连接上发送的数据?
我知道.Net Core可以在Mac和Unix上运行。
Win32 类(例如重叠 I/O)会发生什么情况?I/O 请求数据包如何转换为 Unix?
如果我理解正确的话,那些 win32 类和结构是/和 P/Invoke I/O 指令的基础。asyncawait
据我了解,Linux没有IO完成端口。这可能就是为什么在 Scala (JVM) 中开发人员应该显式通知的
原因API 有关阻塞操作的原因。
然而,任务并行库似乎并没有因为这些细节而困扰开发人员。一切都开箱即用。
但是在 Linux 上使用 Mono/NetCore 时如何避免线程匮乏呢?
linux asynchronous task-parallel-library io-completion-ports .net-core