我将ProgressBar用于控制台命令,并允许该命令在处理过程中的某个点重新启动:

$itemCount = 1_000_000;
$startItem = 150_000;

$progressBar = new ProgressBar($output, $itemCount);
$progressBar->setFormat(
    $progressBar->getFormatDefinition(ProgressBar::FORMAT_DEBUG)
);

$progressBar->start();

if ($startItem !== 0) {
    // unfortunately taken into account in ETA calculation
    $progressBar->advance($startItem);
}

for ($i = $startItem; $i < $itemCount; $i++) {
    usleep(50_000);
    $progressBar->advance();
}

问题是,即使该命令每秒仅处理约20个项目,ETA的计算方法与处理开始时处理了$startItem个项目一样:

150038/1000000 [====>-----------------------]  15% 2 secs/13 secs 20.0 MiB

我预计预计预计到达时间是12小时左右,而不是13秒.

How can I fix this?我是否可以给出进度条before的起始位置,以便正确计算ETA?

推荐答案

ProgressBar助手不支持这一点.

估计时间采用ProgressBar#getEstimated()法计算,非常简单:

public function getEstimated(): float
{
    if (!$this->step) {
         return 0;
    }

    return round((time() - $this->startTime) / $this->step * $this->max);
}

这只考虑了自进度条启动以来的时间量(这是在调用ProgressBar#start()时设置的,或者在构造函数上设置的),以及迄今为止所采取的"步骤"总量.

"真实"步骤和"虚假"步骤之间没有区别.即使在调用start()之前修改ProgresBar#step(例如,在构造函数上),结果也是一样的,因为估算时间的计算方式完全相同.

该类被标记为final,我认为这对于一个helper类来说是不幸的,因此您不能简单地扩展它并添加逻辑(例如,在计算估计剩余时间时可以使用额外的int $resumedAt属性).

如果你真的,真的需要这个,我只需要在你的项目中复制一个类,并在那里添加必要的逻辑.

作为一个简单的概念证明,我将ProgressBar复制到App\ProgressBar中,并添加了以下内容:

private int $resumedSteps = 0;

public function resume(int $max = null, int $step = 0): void
{

    $this->startTime = time();
    $this->resumedStep = $step;
    $this->step = $step;

    if (null !== $max) {
        $this->setMaxSteps($max);
    }

    $this->setProgress($step);

    $this->display();
}

public function getEstimated(): float
{
   if ($this->step === 0 || $this->step === $this->resumedStep) {
      return 0;
   }

   return round((time() - $this->startTime) / ($this->step - $this->resumedStep) * $this->max);
}

public function getRemaining(): float
{
   if ($this->step === 0 || $this->step === $this->resumedStep) {
     return 0;
   }

   return round((time() - $this->startTime) / ($this->step - $this->resumedStep) * ($this->max - $this->step));
}

我们可以简单地将其用作:

$itemCount = 1_000_000;

$progressBar = new App\ProgressBar($output, $itemCount);
$progressBar->setFormat(
    $progressBar->getFormatDefinition(ProgressBar::FORMAT_DEBUG)
);

$startItem > 0 ? $progressBar->resume($startItem) : $progressBar->start();

Php相关问答推荐

基于验证动态更改输入字段类(名称密码)&

在Laravel中,如果我用session—put()存储一些信息,客户端浏览器是否可以使用这些信息?>

以编程方式更新现有Yith WooCommerce Booking的状态

如何使用ms graph php sdk v2列出具有已知路径的DriveItem的子项

Laravel;Composer安装突然返回选项快捷方式不能为空.

Laravel eloquent-如果没有包含InitialValue的结果,则查询where Second Value

来自POST请求的(无效)json字符串中的奇怪字符(编码问题)

我的邮箱中的链接在我的URL中添加了一个

设置WordPress最近的帖子小部件按修改日期排序

PHP 支持 APNG 文件吗?

invalid_grant 和无效的 JWT 签名

Golang - Html 模板:如何创建导航项 - 子菜单?我找不到怎么做

根据所选付款方式更改 WooCommerce 提交结帐按钮文本

htaccess Rewriterule 无法以任何方式工作

Woocommerce单个添加到购物车页面中的产品动态定价

symfony/notifier + twig/inky-extra 在 dunglas/symfony-docker 中缺少 ext-xsl.

Shopware 6:无法在新的自定义插件中保存关联字段(媒体)

使用 --exclude-dir 选项从 PHP 执行 grep 时出现问题

用于多态服务的 Symfony setter 注入

将参数传递给 laravel 9 工厂