为什么cpu绑定更好,阻塞I/O和I/O绑定更好,非阻塞I/O.

piy*_*yal 7 nonblocking blocking cpu-speed

有人告诉我,对于I/O绑定的应用程序,非阻塞I/O会更好.对于CPU绑定应用程序,阻塞I/O要好得多.我找不到这种说法的理由.试过谷歌,但很少有文章只涉及这个话题没有太多细节.有人可以提供深度理由吗?

有了这个,我想清楚自己,非阻塞I/O的缺点是什么.

通过另一个线程会后在这里,一个原因,我可能涉及在外面是如果I/O过程是沉重得那么只有我们使用非阻塞I/O可以看到显著的性能提升.它还指出,如果I/O操作的数量很大(典型的Web应用程序场景),其中有许多请求寻找I/O请求,那么我们也看到使用非阻塞I/O的重大改进.

因此,我的问题归结为以下列表:

  1. 在CPU密集型应用程序的情况下,最好是启动线程池(或scala的executionContext)并在线程池的线程之间划分工作.(我想它肯定比产生自己的线程和手动划分工作更有优势还使用asyn未来概念,甚至可以使用回调返回CPU密集型工作,从而避免与阻塞多线程相关的问题?).此外,如果存在足够快的I/O,则使用线程池本身的线程上的阻塞原则来执行I/O. 我对吗?

  2. 在技​​术上使用非阻塞I/O实际上有什么缺点或开销?如果I/O足够快或者需要的I/O操作非常少,为什么我们看不到使用非阻塞I/O会带来多大的性能提升?最终它是处理I/O的操作系统.无论I/O的数量是大还是小,让操作系统处理这种痛苦.是什么让这里有所不同.

Wer*_*nze 8

从程序员的角度来看,阻塞I/O比非阻塞I/O更容易使用.您只需调用读/写函数,当它返回时您就完成了.使用非阻塞I/O,您需要检查是否可以读/写,然后读/写然后检查返回值.如果不是所有内容都被读取或写入,则需要重新读取的机制或者在写入时可以现在或稍后再次写入.

关于性能:一个线程中的非阻塞I/O并不比阻塞一个线程中的I/O快.I/O操作的速度由读取或写入的设备(例如硬盘)确定.速度不是由等待(阻塞)或不等待(非阻塞)的人决定的.此外,如果您调用阻塞I/O功能,则操作系统可以非常有效地执行阻止.如果您需要在应用程序中执行阻塞/等待,那么您可能会像操作系统那样执行此操作,但您可能也会更糟糕.

那么为什么程序员会更加努力地实现非阻塞I/O呢?因为,这是关键点,他们的程序除了单一的I/O操作之外还有更多的工作要做.使用阻塞I/O时,您需要等待阻塞I/O完成.使用非阻塞I/O时,您可以执行一些计算,直到阻塞I/O完成.当然,在非阻塞I/O期间,您还可以触发其他I/O(阻塞或非阻塞).

非阻塞I/O的另一种方法是使用阻塞I/O引入更多线程,但正如在SO帖子中所说的那样,您链接的线程会产生成本.该成本高于(OS支持的)非阻塞I/O的成本.

如果您的应用程序具有大量I/O但CPU使用率较低,如同并行拥有大量客户端的Web服务器,则使用一些具有非阻塞I/O的线程.使用阻塞I/O会导致很多线程 - >高成本,因此只使用几个线程 - >需要非阻塞I/O.

如果您有一个CPU密集型应用程序,如读取文件的程序,对完整数据进行密集计算并将结果写入文件,则99%的时间将用于CPU密集型部分.因此,创建一些线程(例如,每个处理器一个)并且并行执行尽可能多的计算.关于I/O,您可能会坚持阻止I/O,因为它更容易实现,因为程序并行无关.

如果您的应用程序是CPU密集型和I/O密集型,那么您还可以使用一些线程和非阻塞I/O. 你可以想到一个Web服务器,它有很多客户端和网页请求,你在cgi脚本中进行密集计算.在等待连接上的I/O时,程序可以计算另一个连接的结果.或者想一个读取大文件的程序,可以对文件的块进行密集计算(比如计算平均值或者对所有值加1).在这种情况下,您可以使用非阻塞读取,并在等待下一次读取完成时,您已经可以计算可用的数据.如果结果文件只是一个小的压缩值(如平均值),则可以对结果使用阻塞写入.如果结果文件与输入文件一样大并且类似于"所有值+1",则可以将结果写回非阻塞,并且在写入完成时,您可以自由地对下一个块进行计算.