我熟悉在JVM (Java/nio,Scala/Akka)上根据两种范式(阻塞和非阻塞)进行编程。然而,我看到了一种灰色地带,这让我感到困惑。
看看你选择的任何非阻塞程序:它充满了阻塞语句!
例如,变量的每次赋值都是等待CPU寄存器和内存读取成功的阻塞操作。此外,非阻塞程序甚至包含阻塞语句,这些语句在不违反非阻塞范例的情况下对复杂的内存中集合执行计算。
相反,如果我们以阻塞的方式调用一些外部web服务来接收其结果,那么非阻塞范例显然会被违反。
但在这两个极端之间是什么呢?读/写小文件、本地套接字,或者对嵌入式数据存储引擎(如SQLite、RocksDb等)进行API调用会怎么样呢?是否可以对这些API进行阻塞读/写?它们通常在实践中提供强大的定时保证(例如,只要操作系统没有停顿,<<就是1ms ),因此与纯内存访问几乎没有实际区别。作为一个精确的例子:在Akka Actor中调用RocksDB get/put被认为是不可取的阻塞I/O吗?
因此,我的问题是,是否有经验法则或精确的标准来帮助我决定是否可以在非阻塞程序中坚持使用简单的阻塞语句,或者是否应该将这样的语句封装到非阻塞样板中(取决于框架,例如,将此类调用外包到单独的线程池,在Future或Monad中嵌套更深一步,等等)。
发布于 2017-08-06 04:40:03
例如,变量的每次赋值都是等待
寄存器和内存读取成功的阻塞操作
这不是真正被认为是“阻塞”的东西。这些操作是恒定的时间,与任何IO操作的延迟(数千到数十亿个周期)相比,这个常量非常低(一般只有几个周期)-除了由于交换内存而导致的页面错误,但如果这些错误经常发生,那么无论如何都会有问题。
如果我们想要得到所有挑剔,单独的指令不会完全阻塞CPU线程,因为现代CPU可以重新排序指令,并在等待内存/缓存或其他更昂贵的指令完成时,无序地执行那些没有数据依赖性的指令。
此外,非阻塞程序甚至包含阻塞语句,这些语句在不违反非阻塞范例的情况下对复杂的内存中集合执行计算。
这些并不被认为是阻止CPU执行工作。如果它们被正确地设计为在不阻塞UI的情况下向用户呈现结果,则它们甚至不应该阻止用户交互。
是否可以对这些API进行阻塞读/写?
这总是取决于你为什么首先使用非阻塞方法。你想解决什么问题?也许一个API保证了非阻塞方法,而另一个则不需要。例如,大多数文件IO方法名义上是阻塞的,但没有fsync的写入可能非常便宜,特别是如果您不是在写入旋转的锈蚀,因此在您的计算线程池中避免使用这些方法可能是过度杀伤力。另一方面,人们通常不想在等待数秒的数据库查询时阻塞固定线程池中的线程
https://stackoverflow.com/questions/45525911
复制相似问题