我正在编写一个进度条类,每隔n
个刻度输出一个更新的进度条到std::ostream
:
class progress_bar
{
public:
progress_bar(uint64_t ticks)
: _total_ticks(ticks), ticks_occured(0),
_begin(std::chrono::steady_clock::now())
...
void tick()
{
// test to see if enough progress has elapsed
// to warrant updating the progress bar
// that way we aren't wasting resources printing
// something that hasn't changed
if (/* should we update */)
{
...
}
}
private:
std::uint64_t _total_ticks;
std::uint64_t _ticks_occurred;
std::chrono::steady_clock::time_point _begin;
...
}
我还想输出剩余的时间。我在another question上找到了一个公式,表明剩余时间是(变量名称已更改为适合我的班级):
time_left = (time_taken / _total_ticks) * (_total_ticks - _ticks_occured)
我想要为我的班级填写的部分是time_left
和time_taken
,使用C ++ 11的新<chrono>
标题。
我知道我需要使用std::chrono::steady_clock
,但我不确定如何将其集成到代码中。我认为衡量时间的最佳方法是std::uint64_t
为纳秒。
我的问题是:
<chrono>
中是否有一个函数可以将纳秒转换为std::string
,比如&#34; 3m12s&#34;?std::chrono::steady_clock::now()
,并从_begin
中减去time_left
以确定time_left
吗?答案 0 :(得分:7)
是否存在将纳秒转换为的函数 一个std :: string,比如说“3m12s”?
没有。但我会告诉你如何在下面轻松地做到这一点。
每次更新时都应该使用std :: chrono :: steady_clock :: now() 我的进度条,并从_begin中减去它以确定time_left?
是
是否有更好的算法来确定time_left
是。见下文。
修改强>
我最初误将“滴答”误解为“时钟滴答”,而实际上“滴答”具有工作单位,而_ticks_occurred/_total_ticks
可以解释为%job_done。所以我已相应更改了下面的建议progress_bar
。
我相信等式:
time_left = (time_taken / _total_ticks) * (_total_ticks - _ticks_occured)
不正确。它没有通过完整性检查:如果_ticks_occured == 1
和_total_ticks
很大,那么time_left
大约等于(好,稍微少)time_taken
。这没有意义。
我正在重写上面的等式:
time_left = time_taken * (1/percent_done - 1)
,其中
percent_done = _ticks_occurred/_total_ticks
现在当percent_done
接近零时,time_left
接近无穷大,当percent_done
接近1时,'time_left
接近0.当percent_done
为10%时,{ {1}}是time_left
。这符合我的期望,假设每个工作的时间成本大致是线性的。
9*time_taken
只要你能,就可以在std :: chrono :: durations中进行交易。这样class progress_bar
{
public:
progress_bar(uint64_t ticks)
: _total_ticks(ticks), _ticks_occurred(0),
_begin(std::chrono::steady_clock::now())
// ...
{}
void tick()
{
using namespace std::chrono;
// test to see if enough progress has elapsed
// to warrant updating the progress bar
// that way we aren't wasting resources printing
// something that hasn't changed
if (/* should we update */)
{
// somehow _ticks_occurred is updated here and is not zero
duration time_taken = Clock::now() - _begin;
float percent_done = (float)_ticks_occurred/_total_ticks;
duration time_left = time_taken * static_cast<rep>(1/percent_done - 1);
minutes minutes_left = duration_cast<minutes>(time_left);
seconds seconds_left = duration_cast<seconds>(time_left - minutes_left);
}
}
private:
typedef std::chrono::steady_clock Clock;
typedef Clock::time_point time_point;
typedef Clock::duration duration;
typedef Clock::rep rep;
std::uint64_t _total_ticks;
std::uint64_t _ticks_occurred;
time_point _begin;
//...
};
为您完成所有转化。 typedef可以使用长名称轻松输入。将时间分解为分钟和秒钟就像上面所示一样简单。
正如bames53在他的回答中所说,如果你想使用我的<chrono>
设施,那也很酷。您的需求可能很简单,您不想这样做。这是一个判断电话。 bames53的答案是一个很好的答案。我认为这些额外的细节也可能有所帮助。
修改强>
我不小心在上面的代码中留下了一个错误。而不只是修补上面的代码,我认为指出错误并展示如何使用<chrono_io>
来修复它是个好主意。
错误在这里:
<chrono>
在这里:
duration time_left = time_taken * static_cast<rep>(1/percent_done - 1);
实际上typedef Clock::duration duration;
通常基于整数类型。 steady_clock::duration
将此称为<chrono>
(表示的缩写)。当rep
大于50%时,乘以percent_done
的因子将小于1.当time_taken
为整数时,会将其强制转换为0.所以此{ {1}}仅在前50%期间表现良好,并预测在最后50%期间剩余0时间。
解决此问题的关键是在基于浮点而不是整数的rep
中进行流量传输。 progress_bar
使这很容易做到。
duration
<chrono>
现在与typedef std::chrono::steady_clock Clock;
typedef Clock::time_point time_point;
typedef Clock::period period;
typedef std::chrono::duration<float, period> duration;
具有相同的刻度周期,但使用duration
表示。现在steady_clock::duration
的计算可以省去static_cast:
float
以下是使用这些修复程序的整个软件包:
time_left
没有什么比稍微测试......; - )
答案 1 :(得分:3)
计时库包括用于表示持续时间的类型。您不应该将其转换为某个“已知”单位的平整数。当你想要一个已知的单位时,只需使用计时类型,例如: 'std :: chrono :: nanoseconds'和duration_cast
。或者使用浮点表示和SI比率之一创建自己的持续时间类型。例如。 std::chrono::duration<double,std::nano>
。如果没有duration_cast
或浮点持续时间,则在编译时禁止舍入。
chrono的IO工具没有进入C ++ 11,但你可以从here获得源代码。使用它你可以忽略持续时间类型,它将打印正确的单位。我认为没有任何东西会以分钟,秒等显示时间,但这样的事情不应该太难写。
我不知道有太多理由担心经常拨打显然它会给你带来问题,所以也许你只能在steady_clock::now()
,如果这是你的要求。我希望大多数平台都有一个非常快的计时器来处理这类事情。它确实取决于实现。steady_clock::now()
块内调用if (/* should we update */)
,这应该对呼叫频率设置一个合理的限制
显然,还有其他方法可以估算剩余时间。例如,不是取目前为止的平均值(这是您显示的公式),而是取最后N个刻度的平均值。或者两者都做,并对两个估计值进行加权平均。