PHP Phar在功能强大的PC上创建速度慢,如何加速(加载/读取~3000个文件)?

gre*_*emo 23 php performance phar symfony

我正在尝试使用Phar打包我的Web应用程序(Symfony 2项目).我成功地在一个合理的时间内(1-2分钟)打包了一个带有数百个文件的微框架Silex.

问题在于我的开发机器(i7 4770k,16GB,SSD Raid 0,RAM磁盘上的项目)创建存档非常慢,每个文件需要大约1秒.我真的需要找到一种方法来加快速度.

单次迭代读取/加载文件很慢.我正在使用以下方法添加文件:

function addFile(Phar $phar, SplFileInfo $file)
{
    $root = realpath(__DIR__.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR);
    $path = strtr(str_replace($root, '', $file->getRealPath()), '\\', '/');
    $phar->addFromString($path, file_get_contents($file));
}

$phar = new Phar(/* ... */);
$phar->startBuffering();

// ...    
foreach ($files as $file) {
    addFile($phar, $file);
}

// ...
$phar->setStub(/* ... */);
$phar->stopBuffering();
Run Code Online (Sandbox Code Playgroud)

如何加快阅读/添加文件的速度?可能是我的操作系统(Windows)的问题?

编辑:禁用缓冲并没有解决问题.从字符串添加相同的速度:

// This is VERY fast (~ 1 sec to read all 3000+ files)
$strings = array();
foreach ($files as $file) {
    $root = realpath(__DIR__.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR);
    $path = strtr(str_replace($root, '', $file->getRealPath()), '\\', '/');

    $strings[$path] = file_get_contents($file->getRealPath());
}

// This is SLOW
foreach ($strings as $local => $content) {
    $phar->addFromString($local, $content);
}
Run Code Online (Sandbox Code Playgroud)

编辑:完整的快速和脏脚本(可能有帮助)app/build:

#!/usr/bin/env php
<?php

set_time_limit(0);

require __DIR__.'/../vendor/autoload.php';

use Symfony\Component\Finder\Finder;
use Symfony\Component\Console\Input\ArgvInput;

$input = new ArgvInput();
$env = $input->getParameterOption(array('--env', '-e'), 'dev');

function addFile(Phar $phar, SplFileInfo $file)
{
    $root = realpath(__DIR__.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR);
    $path = strtr(str_replace($root, '', $file->getRealPath()), '\\', '/');
    $phar->addFromString($path, file_get_contents($file));
}

$phar = new Phar(__DIR__ . "/../symfony.phar", 0, "symfony.phar");
$phar->startBuffering();

$envexclude = array_diff(array('dev', 'prod', 'test'), array($env));

// App
$app = (new Finder())
    ->files()
    ->notPath('/cache/')
    ->notPath('/logs/')
    ->notName('build')
    ->notname('/._('.implode('|', $envexclude).')\.yml$/')
    ->in(__DIR__);

// Vendor
$vendor = (new Finder())
    ->files()
    ->ignoreVCS(true)
    ->name('*.{php,twig,xlf,xsd,xml}')
    ->notPath('/tests/i')
    ->notPath('/docs/i')
    ->in(__DIR__.'/../vendor');

// Src
$src = (new Finder())
    ->files()
    ->notPath('/tests/i')
    ->in(__DIR__.'/../src');

// Web
$web = (new Finder())
    ->files()
    ->in(__DIR__.'/../web')
    ->notname('/._('.implode('|', $envexclude).')\.php$/');

$all = array_merge(
    iterator_to_array($app),
    iterator_to_array($src),
    iterator_to_array($vendor),
    iterator_to_array($web)
);

$c = count($all);
$i = 1;
$strings = array();
foreach ($all as $file) {
    addFile($phar, $file);
    echo "Done $i/$c\r\n";
    $i++;
}

$stub = <<<'STUB'
Phar::webPhar(null, "/web/app_phar.php", null, array(), function ($path) {
    return '/web/app_phar.php'.$path;
});

__HALT_COMPILER();
STUB;

$phar->setStub($stub);
$phar->stopBuffering();
Run Code Online (Sandbox Code Playgroud)

Fuz*_*ree 11

尝试使用Phar :: addFile($ file)而不是Phar :: addFromString(file_get_contents($ file))

function addFile(Phar $phar, SplFileInfo $file)
{
    $root = realpath(__DIR__.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR);
    $path = strtr(str_replace($root, '', $file->getRealPath()), '\\', '/');
    //$phar->addFromString($path, file_get_contents($file));
    $phar->addFile($file,$path);
}
Run Code Online (Sandbox Code Playgroud)


小智 9

Phar::addFromString()或是Phar:addFromFile()非常慢.就像@sectus说 Phar::buildFromDirectory() 的要快得多.但作为一种简单的替代方案,您可以使用对代码进行少量更改Phar::buildFromIterator().

例:

$all = $app->append($vendor)->append($src)->append($web);
$phar->buildFromIterator($all, dirname(__DIR__));
Run Code Online (Sandbox Code Playgroud)

代替:

$all = array_merge(
    iterator_to_array($app),
    iterator_to_array($src),
    iterator_to_array($vendor),
    iterator_to_array($web)
);

$c = count($all);
$i = 1;
$strings = array();
foreach ($all as $file) {
    addFile($phar, $file);
    echo "Done $i/$c\r\n";
    $i++;
}
Run Code Online (Sandbox Code Playgroud)

$ time app/build

real    0m4.459s
user    0m2.895s
sys     0m1.108s
Run Code Online (Sandbox Code Playgroud)

在我非常慢的ubuntu机器上花费<5秒.

  • 最好的答案,从10:39到00:10 (2认同)