【问题标题】:O_NONBLOCK unexpected behaviorO_NONBLOCK 意外行为
【发布时间】:2011-10-25 03:38:44
【问题描述】:

我正在使用套接字并使用 fcntl 设置 O_NONBLOCK,但仍然通过消耗 100% CPU 的应用程序。即使我正在使用等待时间为 1 毫秒的选择。

出于阅读目的,我使用recv。

我在没有 O_NONBLOCK 的情况下尝试了它,在这种情况下它不会消耗 100% 的 CPU,但 recv 需要很多时间。我尝试使用 O_NONBLOCK 选项进行 recv,但仍需要花费大量(有时 200 毫秒)时间来读取 recv。 我们正在使用 select 那为什么 recv 需要很多时间?

我不能使用第一个选项(带有 O_NONBLOCK 的套接字),因为 CPU 已被消耗,而在第二个选项中存在时间延迟。

任何人都可以提出意见。它是一个客户端应用程序。

【问题讨论】:

  • "为了读取目的,使用 recv 并且一旦不设置 O_NONBLOCK 则它不会消耗 100% CPU,如果在这种情况下,使用 O_NONBLOCK 选项的 recv 会花费很多时间来读取值。"

标签: c linux sockets unix networking


【解决方案1】:

select() 被优化为在您使用更长的超时时间时进入有效的等待状态(不消耗太多 CPU)。尝试 30 秒。当监视的文件描述符之一发生活动时,它将立即返回,因此您可以完成工作。

尝试在 strace -v -ttt 或 tcpdump 下查看您的进程,以寻找高延迟的提示,或显示相关代码。

还要注意 select 可以改变 timeval 结构,所以记得在 select() 调用之间重置值。

【讨论】:

  • 30 秒有点多。对于用户请求的操作来说,大约 1.5 - 2 秒是好的,让他们有机会在网络访问不工作时取消(例如错误的对等地址或网络故障)
  • 时间真的取决于您需要服务的选择之外的其他事件。对于仅在蓝月亮中关闭一次的非交互式守护程序来说,30 秒可能还不错。如果您的进程有另一个线程在运行rm -rf / :-),则可能需要一毫秒
  • 同意 30s 有点过分了,但是 select() 也可以自动被信号打断。无论如何,它应该是可配置的:)。我怀疑 OP 正在进入 recv() 和/或 select() 的繁忙循环 - strace 应该显示这一点。
  • 如果您必须退出选择循环来轮询某些内容,那么您的应用程序设计不佳。信号处理程序无论如何都不能做任何重要的工作,所以让他们写下选择监视的哨兵管道很容易。同样对于用户输入 - 将 X 套接字或标准输入连接到选择。等等。除非您实际上有一个必须在特定时间发生的事件,否则几乎没有理由让选择有任何超时。
【解决方案2】:

我认为这并不意外。如果您设置非阻塞模式,recv 将不会阻塞等待某事。换句话说,无论数据是否可用,它都会返回,这非常可能会占用你的 CPU。

我还会考虑稍微增加select 超时时间。没有真正的理由让它这么小,因为这可能会占用 CPU。

我倾向于为select 超时使用像秒这样的值,因为这是我在其他事情上需要的延迟时间(比如及时处理 CTRL-BREAK 信号)。

这在等待数据可用时为进程提供了大量非 CPU 密集型时间。如果它在不到秒内可用,那么您会更早知道它(select 将返回)。

【讨论】:

  • select() 将阻塞,即使您在其中一个 FD_SET 中有 O_NONBLOCK 套接字。 O_NONBLOCK 用于 i/o,而不是边缘触发的就绪通知。
  • @ggiroux:这并不重要,但select 是水平触发的,而不是边缘触发的。
  • 是的,对不起,我很困惑,忘了这一点,自从我发表评论以来,pax 也澄清了他的回答。
猜你喜欢
  • 2017-03-10
  • 2019-05-01
  • 2011-07-15
  • 2011-04-27
  • 2019-12-07
  • 2021-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多