阻塞和非阻塞I / O之间的灰色区域?

时间:2017-08-05 20:01:57

标签: multithreading jvm akka blocking nonblocking

我很熟悉在JVM(Java / nio,Scala / Akka)上根据两种范例(阻塞和非阻塞)进行编程。 但是,我看到中间有一种灰色区域让我困惑。

查看您选择的任何非阻塞程序:它充满了阻止声明!

例如,变量的每个赋值都是一个阻塞操作,它等待CPU寄存器和内存读取成功。 此外,非阻塞程序甚至包含阻塞语句,可以在复杂的内存集合中进行计算,而不会违反非阻塞范例。

与此相反,如果我们以阻塞的方式调用某些外部网络服务来接收其结果,那么非阻塞范式显然会被违反。

但这些极端之间究竟是什么?如何读取/写入小文件,本地套接字或对嵌入式数据存储引擎(如SQLite,RocksDb等)进行API调用。是否可以阻止对这些API的读/写操作?它们通常在实践中提供强大的定时保证(例如,只要OS没有停止,<&lt; <1ms),因此对于纯内存访问几乎没有实际差异。作为一个确切的例子:调用RocksDBs获取/放入被认为是不可取的阻塞I / O的Akka Actor中?

所以,我的问题是,是否有经验法则或精确标准可以帮助我决定是否可以在非阻塞程序中坚持使用简单的阻塞语句,或者是否将此类语句包含在非阻塞语句中样板(取决于框架,例如,将这种调用外包给一个单独的线程池,在Future或Monad中更深入地嵌套,等等。)

1 个答案:

答案 0 :(得分:2)

  例如,每个变量赋值都是一个阻塞操作,等待CPU寄存器和内存读取成功

这并不是什么被认为是“阻塞”。这些操作是恒定时间,并且与任何IO操作的延迟(数千到数十亿个周期之间的任何时间)相比,该常量非常低(一般为几个周期) - 除了由于交换内存导致的页面错误,但是如果发生这些操作经常你有问题。

如果我们想得到所有的挑剔,单独的指令不能完全阻止CPU线程,因为现代CPU可以重新排序指令并执行那些没有数据依赖性的乱序,同时等待内存/缓存或其他更昂贵的指令光洁度。

  

此外,非阻塞程序甚至包含阻塞语句,可以对复杂的内存中集合进行计算,而不会违反非阻塞范例。

这些不被视为阻止CPU执行工作。如果它们被正确设计为在没有阻止UI的情况下将结果呈现给用户,它们甚至不应该阻止用户交互。

  

是否可以对这些API进行阻止读/写操作?

这始终取决于您首先使用非阻塞方法的原因。你想解决什么问题?也许一个API保证采用非阻塞方法,而另一个则不保证。 例如,大多数文件IO方法名义上都是阻塞的,但是没有fsync的写入可能非常便宜,特别是如果您没有写入旋转生锈,那么在计算线程池上避免使用这些方法可能会过度。另一方面,通常不希望在等待多秒数据库查询时阻塞固定线程池中的线程