Có chức năng nào trong đó sẽ chuyển đổi nano giây thành chuỗi std ::, ví dụ như "3m12s"?
No.Nhưng tôi sẽ chỉ cho bạn cách bạn có thể dễ dàng thực hiện việc này bên dưới.
Tôi có nên sử dụng tiêu chuẩn :: chrono :: steady_clock :: now() mỗi lần tôi cập nhật thanh tiến trình của mình và trừ từ _begin để xác định time_left?
Có.
Có một thuật toán tốt hơn để xác định TIME_LEFT
Yes. Xem bên dưới.
Sửa
Ban đầu tôi đã hiểu sai "ve" là "đồng hồ tíc tắc", trong khi thực tế "tíc tắc" có các đơn vị của công việc và _ticks_occurred/_total_ticks
thể được hiểu là% job_done. Vì vậy, tôi đã thay đổi đề xuất progress_bar
bên dưới cho phù hợp.
tôi tin rằng phương trình:
time_left = (time_taken/_total_ticks) * (_total_ticks - _ticks_occured)
là không chính xác. Nó không vượt qua một kiểm tra sanity: Nếu _ticks_occured == 1
và _total_ticks
là lớn, sau đó time_left
xấp xỉ bằng (ok, hơi ít) time_taken
. Điều đó không có ý nghĩa.
Tôi viết lại phương trình trên là:
time_left = time_taken * (1/percent_done - 1)
nơi
percent_done = _ticks_occurred/_total_ticks
Bây giờ là percent_done
tiếp cận zero, time_left
tiến tới vô cùng, và khi percent_done
tiếp cận 1, 'time_left
tiếp cận 0. Khi percent_done
là 10%, time_left
là 9*time_taken
. Điều này đáp ứng được sự mong đợi của tôi, giả sử chi phí thời gian tuyến tính cho mỗi công việc-tick.
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;
//...
};
Giao thông trong std :: chrono :: thời gian bất cứ khi nào bạn có thể. Bằng cách đó, <chrono>
thực hiện tất cả các chuyển đổi cho bạn. typedefs có thể dễ dàng gõ với tên dài. Và chia nhỏ thời gian thành phút và giây dễ dàng như được trình bày ở trên.
Như bames53 ghi chú trong câu trả lời của mình, nếu bạn muốn sử dụng cơ sở <chrono_io>
của tôi, điều đó cũng thật tuyệt. Nhu cầu của bạn có thể đủ đơn giản mà bạn không muốn. Đó là một cuộc gọi phán xét. Câu trả lời của bames53 là một câu trả lời hay. Tôi nghĩ những chi tiết bổ sung này cũng có thể hữu ích.
Sửa
tôi vô tình để lại một lỗi trong đoạn code trên. Và thay vì chỉ vá mã ở trên, tôi nghĩ sẽ là một ý hay khi chỉ ra lỗi và chỉ cách sử dụng <chrono>
để sửa lỗi.
Lỗi là ở đây:
duration time_left = time_taken * static_cast<rep>(1/percent_done - 1);
và ở đây:
typedef Clock::duration duration;
Trong thực tế steady_clock::duration
thường dựa trên một loại không thể thiếu. <chrono>
gọi đây là số rep
(viết tắt là đại diện). Và khi percent_done
lớn hơn 50%, hệ số nhân với time_taken
sẽ nhỏ hơn 1. Và khi rep
là tích phân, được đúc thành 0. Vì vậy, progress_bar
chỉ hoạt động tốt trong 50% đầu tiên và dự đoán 0 thời gian còn lại trong 50% cuối cùng.
Chìa khóa để sửa lỗi này là lưu lượng truy cập trong duration
s dựa trên điểm động thay vì số nguyên. Và <chrono>
làm cho việc này rất dễ thực hiện.
typedef std::chrono::steady_clock Clock;
typedef Clock::time_point time_point;
typedef Clock::period period;
typedef std::chrono::duration<float, period> duration;
duration
nay đã có khoảng thời gian đánh dấu giống như steady_clock::duration
nhưng sử dụng một float
cho đại diện. Và bây giờ tính toán cho time_left
có thể rời khỏi static_cast:
duration time_left = time_taken * (1/percent_done - 1);
Dưới đây là toàn bộ gói lại với các bản sửa lỗi:
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<minutes>(time_left);
seconds seconds_left = duration_cast<seconds>(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<float, period> duration;
std::uint64_t _total_ticks;
std::uint64_t _ticks_occurred;
time_point _begin;
//...
};
Không có gì giống như một thử nghiệm nhỏ ... ;-)
Lý do cho "đánh dấu" là đại diện cho tiến độ, tức là: Tôi có 1.000.000 hoạt động (bọ ve) để hoàn thành. Từ những gì tôi có thể nói, boost có 'chrono_io'. Bạn có đề nghị sử dụng nó không? – nerozehl
Ồ, "đánh dấu" đại diện cho một đơn vị công việc, không phải là một đơn vị thời gian? Nếu vậy, tôi hiểu lầm câu hỏi của bạn. Tôi nhầm lẫn đọc "đồng hồ đánh dấu". Tăng cường ' 'là bản sao được ủy quyền của' '. Nó sẽ là tốt để sử dụng nếu bạn thấy nó hữu ích. Tôi đang đề xuất ' 'cho một tiêu chuẩn trong tương lai, vì vậy sẽ rất tốt khi có phản hồi về nó. –
Có đánh dấu là một đơn vị công việc .. Tôi cho rằng tôi nên rõ ràng hơn, tôi xin lỗi vì những rắc rối về điều đó. Cảm ơn nhiều! :) – nerozehl