PHP是否以静默方式将连续的fseek命令优化为一个fseek命令?

PHP是否以静默方式将连续的fseek命令优化为一个fseek命令?,php,performance,windows-7,32bit-64bit,internal,Php,Performance,Windows 7,32bit 64bit,Internal,我运行的是Windows7-64位,最新的XAMPP版本有32位的PHP版本 关于测试 对于一个非常大的文件(大于PHP_MAX_INT 2147483647),我现在非常确定,在对filepointer执行之前,会对连续的以下fseek进行汇总 我有两个问题: 我可以用合理的方法(或者只使用上面链接中提到的解决方法)打破这个总结吗 这种聚合是在PHP中发生的(我假设,虽然我不知道在PHP中发生了什么),还是在Windows7中发生的 回答我自己:尝试两种解决方法和多个搜索都不起作用 在我的系统

我运行的是Windows7-64位,最新的XAMPP版本有32位的PHP版本

关于测试 对于一个非常大的文件(大于PHP_MAX_INT 2147483647),我现在非常确定,在对filepointer执行之前,会对连续的以下fseek进行汇总

我有两个问题:

  • 我可以用合理的方法(或者只使用上面链接中提到的解决方法)打破这个总结吗

  • 这种聚合是在PHP中发生的(我假设,虽然我不知道在PHP中发生了什么),还是在Windows7中发生的

  • 回答我自己:尝试两种解决方法和多个搜索都不起作用 在我的系统上。相反,他们将文件指针放在不同的位置 在PHP_MAX_INT以下。(32位PHP最多只能搜索PHP_MAX_INT。)+ 从那里开始阅读仍然是可能的,但我不知道有多远。)

    因此,对于我的具体案例,这个问题已经过时了 无论您做什么,32位PHP最多只能搜索PHP_MAX_INT+8192。我 别提这个问题,因为有两个人投了赞成票,而且可能是 对一般答案感兴趣

    我在这里提交了一份bug报告:


    结果:对于64位PHP构建,它可能会工作,但我没有尝试过。

    它没有。它实际上做了一些更愚蠢的事情。下面是PHP源代码的一个片段:

          switch(whence) {
              case SEEK_CUR:
                  offset = stream->position + offset;
                  whence = SEEK_SET;
                  break;
          }
    
    这是PHP的
    fseek
    实现的核心。这里发生的事情是:如果您告诉PHP从当前位置进行搜索,它会从文件开始将其转换为“等效”搜索。这仅在偏移量计算不溢出时有效;如果是,那么,
    offset
    是一个有符号整数,所以这是未定义的行为

    好的,这是因为PHP缓冲区内部有流,所以它们需要做一些事情。但不一定是这样


    您最好尝试使用一种语言来完成您的工作,这种语言能够真正做到您告诉它的内容。

    如果要进行聚合,那么它可能必须作为操作码优化,或者必须通过缓冲区在较低级别上进行

    我可以回答低层次的问题。php中的fseek()是使用php流实现的。它在ext/standard/file.h中声明,在.c中定义。它的实现调用php_stream_seek(),该函数调用streams.c中的_php_stream_seek()。这种方法的底层实现是通过普通流包装器来处理的,在这种情况下,seek调用通过zend_seek或zend_fseek进行,而zend_fseek又通过32位或64位seek_seeki64 c调用进行映射

    所以。。。如果发生任何聚合,它似乎必须在操作码优化中,甚至在操作系统或硬件中。硬盘实现无序抓取以减少磁头寻道距离,文件系统缓冲系统可能能够减少无副作用的寻道。如果您关心磁盘读取时间,第一个会自动处理。如果您担心可能会破坏内存(不必要地在缓冲区中寻找很远的距离),您可能会考虑另一种方法。有关磁盘如何避免浪费寻道时间的更多信息,请参阅


    我希望这能有所帮助。

    注意:我没有按照别人的建议尝试SplFileObject,因为我相信php手册中的SplFileObject应该只是普通seek等命令之上的一层。我已经为这个特定的任务迁移到了perl。(连php bug方面的人都理解。)我不会部署64位php构建,只要它不是主流。我并不是为了读写几个非常大的文件而完全迁移到perl。(对我来说,很难看出SplFileObject在概念上有什么优势。尽管据说维护人员对此很“热情”)这其实不应该是个问题,因为读写点的更改会减少到与当前位置的偏移量,磁盘系统不会执行不必要的查找;它只是去寻找它需要读和写的头部。从这个意义上讲,不读不写的查找就是改变有符号整数。摘下你的彩色眼镜。这些语义意味着,即使文件系统和操作系统能够查找,PHP程序也无法在文件中查找比
    ZEND_LONG_MAX
    字节更多的字节。因为PHP对SEEK\u CUR的实现包含了形式上的、C标准意义上的未定义行为。在这种情况下,PHP不会执行程序员让它执行的操作,这应该是不可接受的。@Alex:这符合我通过尝试不同的目标搜索值所发现的情况。(请参阅我链接的php bug报告中的最后一项。)因此我接受这个答案。由于存在bug(或旧代码),如果在其他级别上存在其他优化或bug,则当前对最终用户没有任何影响,因为这些其他级别永远不会获得假定值。我想是吧。我不喜欢这个。如前所述,我将perl用于单个大文件任务。:)也许您可以用找到的代码行编写一个bug报告,也许它会得到改进。:)@亚历克斯:顺便说一句:32位php只能保证达到它所能工作的大小。:)我只是想知道,在php手册网页上发布的链接不起作用的解决方案怎么会得到这么多的投票。也许是以前的版本。或者当php与其他编译器一起编译时。-反正太难了。再加上在windows上写入和读取UTF文件名的问题,php对我失去了一点吸引力。@Alex我的回答是基于对php源代码的读取,没有考虑其他因素,只是磁盘系统会优化磁盘上不必要的搜索。ZEND_LONG_MAX是一个LONG,在64位系统上是64位的。类似地,正如我在回答中指出的,在PHP源代码中,zend_fseek根据系统映射到seek或seeki64。因此,PHP应该能够在vir中找到任何位置