我知道非阻塞接收在消息传递中没有被使用,但仍有一些直觉告诉我,它是必需的。以GUI事件驱动的应用程序为例,您需要某种方式以非阻塞方式等待消息,因此您的程序可以执行一些计算。解决此问题的方法之一是使用带有消息队列的特殊线程。是否有一些用例,即使你有线程,你真的需要非阻塞接收?
答案 0 :(得分:4)
线程与非阻塞异步操作的工作方式不同,尽管通常可以通过执行同步操作的线程来实现相同的效果。然而,最终,它归结为如何更有效地处理事情。
线程是有限的资源,应该用于处理长时间运行的活动操作。如果你有一些不是真正活跃的东西,但需要等待一段时间才能得到结果(想想通过网络进行一些I / O操作,比如调用Web服务或数据库服务器),那么最好使用提供的它的异步替代方法,而不是通过将同步调用放在另一个线程上而不必要地浪费线程。
为了便于理解,您可以对此问题 here 进行详细阅读。
答案 1 :(得分:2)
每个连接一个线程通常不是一个好主意(浪费内存,并非所有操作系统都非常适合大量线程计数等)
你如何打断阻止接听电话?例如,在Linux上(可能在某些其他POSIX OS上)pthreads + signals = disaster。使用非阻塞接收,您可以在接收套接字上复用您的等待,以及用于在线程之间进行通信的某种IPC套接字。还可以相对轻松地映射到Windows世界。
如果您需要使用更复杂的东西(例如OpenSSL)替换常规套接字,依赖阻塞行为可能会让您遇到麻烦。例如,OpenSSL可能会在阻塞套接字上死锁,因为SSL协议具有发送/接收反转方案,在发送完成之前无法继续接收。
我的经验是 - “当有疑问时使用非阻塞套接字”。
答案 2 :(得分:2)
通过阻止IO,在许多平台上,让您的应用程序在面对缓慢,挂起或断开连接的客户端/服务时尽快有序关闭时,具有挑战性。
使用非阻塞IO,您可以在系统调用返回后立即终止正在进行的操作。如果您的代码编写时考虑了提前终止 - 这对于非阻塞IO来说相对简单 - 这可以让您优雅地清理已保存的状态。
答案 3 :(得分:1)
我无法想到,但有时非阻塞API的设计方式使得它们比明确的多线程实现更容易/更直观。
答案 4 :(得分:1)
这是我最近遇到的一个真实情况。以前我有一个每小时运行一次的脚本,由crontab管理,但有时用户会登录到机器并手动运行脚本。这有一些问题,例如crontab和用户的并发执行可能会导致问题,有时用户会以root身份登录 - 我知道,糟糕的模式,不在我的控制之下 - 并运行具有错误权限的脚本。所以我们决定让例程作为守护进程运行,具有适当的权限,并且用户用来运行的命令现在只是触发守护进程。
因此,这个用户执行的命令基本上会做两件事:触发守护进程并等待它完成任务。但它还需要超时并在等待时继续将守护程序日志转储给用户。
如果我理解你提出的情况,我就有了你想要的情况:我需要继续监听守护进程,同时仍然独立地与用户交互。该解决方案是异步读取。
幸运的是,我没有考虑使用线程。如果我用Java编写代码,我可能会这么想,但这是Python代码。
答案 5 :(得分:0)
我的观点是,当我们认为线程和消息传递是完美的时,真正的权衡是编写调度程序来规划非阻塞接收操作,并为具有共享状态(锁等)的线程编写同步代码。我会说,两者都有时很容易,有时很难。因此,一个用例就是当有许多消息要接收异步消息时,以及何时根据消息操作很多数据。这在使用非阻塞接收的一个线程中非常容易,并且会要求与许多线程和共享状态进行很多同步....我也在考虑一些现实生活中的例子,我稍后会包含它。