我在这里阅读有关JavaScript输出缓冲的内容,并且试图让我的头脑绕过作者所说的在打印1到1,000,000网页时最快的脚本.(向下滚动到标题"获胜的一百万个数字脚本".)稍微研究一下后,我有几个问题:
是什么让这个脚本与其他方法相比如此高效?
为什么缓冲加快了速度?
如何确定要使用的适当缓冲区大小?
这里有没有人有任何可以进一步优化这个脚本的技巧?
(我意识到这可能是CS101,但我是那些受过抨击的,自学成才的黑客之一,而且我希望能从这一方面的集体智慧中受益.谢谢!)
作者正在对此算法进行多项优化.这些中的每一个都需要相当深入地理解所使用的底层机制(例如Javascript,CPU,寄存器,缓存,视频卡等).我认为他正在进行两项关键优化(其余只是结冰):
缓冲输出
使用整数数学而不是字符串操作
我会很快讨论缓冲,因为你明确地询问它.他正在使用的整数数学有两个性能优势:整数加法每个操作比字符串操作更便宜,并且它使用更少的内存.
我不知道JavaScript和Web浏览器如何处理浏览器中整数到显示字形的转换,因此与字符串相比,将整数传递给document.write可能会有一些损失.但是,他正在执行(1,000,000/1000)document.write调用,而不是1,000,000 - 1,000个整数添加.这意味着他正在执行大约3个数量级的操作来形成消息,而不是将其发送到显示器.因此,将一个整数与一个字符串发送到document.write的代价必须超过3个数量级才能抵消操纵整数的性能优势.
其工作原理的具体细节取决于您使用的平台,硬件和实现.无论如何,它都是关于平衡你的算法与你的瓶颈诱导资源.
例如,在文件I/O的情况下,缓冲区是有用的,因为它利用了旋转磁盘一次只能写入一定量的事实.给它太少的工作,当磁盘旋转时,它不会使用在主轴头部下方通过的每个可用位.给它太多,你的应用程序必须等待(或者进入睡眠状态)磁盘完成你的写入时间,这可能花费在准备写下一条记录上!确定文件I/O的理想缓冲区大小的一些关键因素包括:扇区大小,文件系统块大小,交错,磁头数,旋转速度和面密度等.
在CPU的情况下,它是关于保持管道满的全部.如果你给CPU太少的工作,它将花费时间旋转NO OPs等待你的任务.如果给CPU太多,则可能不会将请求分派给可以并行执行的其他资源,例如磁盘或视频卡.这意味着以后在CPU上必须等待这些返回而无需做任何事情.CPU中缓冲的主要因素是使您需要的所有内容(对于CPU)尽可能靠近FPU/ALU.在典型的体系结构中,这是(按照接近度降低的顺序):寄存器,L1高速缓存,L2高速缓存,L3高速缓存,RAM.
在向屏幕写入一百万个数字的情况下,它是关于使用视频卡在屏幕上绘制多边形.想想这样.假设对于添加的每个新号码,视频卡必须进行100,000,000次操作才能在屏幕上绘制多边形.在一个极端情况下,如果一次在页面上放置一个数字,然后将您的视频卡写出来并为1,000,000个数字执行此操作,那么视频卡将需要执行10 ^ 14次操作 - 100万亿次操作!在另一个极端情况下,如果您将整个100万个数字一次性发送到视频卡,则只需100,000,000次操作.最佳点是在中间的某些位置.如果你这样做一次,CPU会做一个工作单元,并在GPU更新显示器时等待很长时间.
除非您针对具有特定算法的非常具体且定义明确的平台(例如,为互联网路由编写数据包路由),否则通常无法通过数学方式确定此问题.通常,你会凭经验找到它.猜一个值,试一试,记录结果然后选择另一个.您可以根据您管理的瓶颈,对从何处开始以及调查范围进行一些有根据的猜测.
我不知道这是否会起作用,但我还没有测试过,但缓冲区大小通常是2的倍数,因为计算机的底部固定是二进制的,字大小通常是两倍的倍数(但情况并非总是这样!).例如,64字节更可能是最优的60字节,1024更可能是最佳的1000.这个问题的一个瓶颈是迄今为止的大多数浏览器(谷歌Chrome是我的第一个例外)知道)让javascript在与网页渲染机制的其余部分相同的线程中连续运行.这意味着javascript做了一些填充缓冲区的工作,然后等待很长时间,直到document.write调用返回.如果javascript作为单独的进程运行,异步,就像在chrome中一样,你可能会获得一个大的加速.这当然是攻击瓶颈的来源而不是使用它的算法,但有时候这是最好的选择.
不像我想的那样简洁,但希望这是一个很好的起点.缓冲是计算中各种性能问题的重要概念.充分了解代码使用的基础机制(包括硬件和软件)对于避免或解决性能问题非常有用.