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