Is there a function in that will convert the nanoseconds into
an std::string, say something like “3m12s”?
不,但我会告诉你如何轻松地在下面这样做.
Should I use the std::chrono::steady_clock::now() each time I update
my progress bar, and subtract that from _begin to determine time_left?
是.
Is there a better algorithm to determine 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大约等于(ok,略少)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%时,time_left为9 * time_taken.这符合我的期望,假设每个工作的时间成本大致是线性的.
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(1/percent_done - 1);
minutes minutes_left = duration_cast(time_left);
seconds seconds_left = duration_cast(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;
//...
};
只要你可以,就可以在std :: chrono :: durations中进行交易.那样< chrono>为你完成所有转换. typedef可以使用长名称轻松输入.将时间分解为分钟和秒钟就像上面所示一样简单.
正如bames53在他的回答中所说,如果你想使用我的< chrono_io>设施,这也很酷.您的需求可能很简单,您不想这样做.这是一个判断电话. bames53的答案是一个很好的答案.我认为这些额外的细节也可能有所帮助.
编辑
我不小心在上面的代码中留下了一个错误.而不只是修补上面的代码,我认为指出错误并展示如何使用< chrono>是一个好主意.要解决这个问题.
错误在这里:
duration time_left = time_taken * static_cast(1/percent_done - 1);
和这里:
typedef Clock::duration duration;
实际上,steady_clock :: duration通常基于整数类型. 将此称为rep(表示的缩写).并且当percent_done大于50%时,乘以time_taken的因子将小于1.并且当rep为积分时,将其转换为0.因此,progress_bar仅在前50%期间表现良好并且预测0时间在过去的50%中离开了.
解决这个问题的关键是基于浮点而不是整数来计算持续时间.并且< chrono>使这很容易做到.
typedef std::chrono::steady_clock Clock;
typedef Clock::time_point time_point;
typedef Clock::period period;
typedef std::chrono::duration duration;
duration现在具有与steady_clock :: duration相同的tick周期,但使用float表示.现在time_left的计算可以不使用static_cast:
duration time_left = time_taken * (1/percent_done - 1);
以下是使用这些修复程序的整个包:
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 * (1/percent_done - 1);
minutes minutes_left = duration_cast(time_left);
seconds seconds_left = duration_cast(time_left - minutes_left);
std::cout << minutes_left.count() << "m " << seconds_left.count() << "s\n";
}
}
private:
typedef std::chrono::steady_clock Clock;
typedef Clock::time_point time_point;
typedef Clock::period period;
typedef std::chrono::duration duration;
std::uint64_t _total_ticks;
std::uint64_t _ticks_occurred;
time_point _begin;
//...
};
没有什么比一点测试…… 😉