在 macOS 中使用 boost.asio 协程会触发大量文件描述符

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

我有一个程序,使用 async_read 和来自 unix 域套接字的收益。

void readSocket(const std::list<std::shared_ptr<IpcSocket>>::iterator &socket,
                boost::asio::yield_context yield) {
.....
  while (1) { 
    HeaderStruct hdr;
    boost::asio::async_read((*socket)->socket, 
                            boost::asio::buffer(&hdr, sizeof(hdr)),
                            boost::asio::transfer_all(), yield);
.....
  }
}

似乎在极端情况下,当系统因到达进程可以处理的更高粘贴的请求而过载时,我达到进程打开文件描述符已超过最大值的临时状态。

查看

lsof
显示几乎所有打开的文件描述符都是为双向管道创建的,还有一个是为 KQUEUE 创建的。根据我的观察,async_read 中的协程暂停是通过触发这 3 个文件描述符的
select
系统调用来实现的。

myProg   83099 root  184u   KQUEUE                                                 count=1, state=0x8
myProg   83099 root  185      PIPE 0x432799c5a6f5943f    16384                     ->0x28a17a0822a260f7
myProg   83099 root  186      PIPE 0x28a17a0822a260f7    16384                     ->0x432799c5a6f5943f

我想知道我关于 select 系统调用触发这 3 个文件描述符的理论是否正确(我使用 dtrace 在处理来自套接字的读取请求时监视系统调用),如果是,我该如何避免呢?我应该用常规异步调用替换协程,还是在分离线程上使用同步读取?

谢谢

c++ boost boost-asio system-calls
1个回答
0
投票

您提到的文件描述符与异步I/O的内部机制有关,并不直接对应于您打开的Unix域套接字。您关于触发这些描述符的 select 系统调用的理论并不完全准确。

在您提供的代码中,async_read 是一种执行非阻塞 I/O 的协程友好方式。它不直接使用 select 或 poll,而是依赖 Boost.Asio 的内部机制来处理 I/O 事件,其中可能涉及 epoll 或 kqueue(在类 Unix 系统上)等机制。

您可以尝试增加程序可以使用的文件描述符的最大数量。在许多系统上,您可以通过修改 /etc/security/limits.conf 或 /etc/security/limits.d/ 文件或使用 ulimit 命令来执行此操作。但是,通常不建议这样做,因为它可能会对系统范围产生影响。

实现请求限流机制,限制可以并发处理的请求数量。这可以帮助减轻文件描述符的压力并防止系统过载。

如果增加文件描述符限制还不够,您可以考虑将部分处理移至单独的线程。这可以帮助分配负载并减少每个线程打开的文件描述符的数量。

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