我应该以及如何在c++中创建需要计算的算法的进度报告

Should I and how do I create progress reporting in computation demanding algorithms in c++

本文关键字:计算 算法 报告 创建 c++ 我应该      更新时间:2023-10-16

我正在实现一些深度学习神经网络,现有的Matlab代码通常只是打印到控制台,这样用户就有了一个进度的想法。

当我为c++做设计时,我把算法的核心部分放在单独的函数中,我不想把东西打印到控制台,有没有办法或设计原则给使用算法的用户留下一个选项来获得某种进度指示?

可以让一个可选参数是一个函数指针,人们可以钩到,或者我该怎么做?

void my_heavy_algorithm(int * data, int n,...);

如果你要将你的算法作为一个函数集合,那么你应该让其中一个参数是一个函数指针,并带有这样的签名:

void (*reportProgress)(void*, int)

但是如果你在c++中设计你的算法,你可能应该利用封装并为你的算法创建一个类(或一组类)。在这种情况下,您不希望将函数指针作为参数添加到单个函数中。

而可以使函数指针成为类的成员。并有访问器方法来获取/设置它。或者更好的是,提供一个抽象类来报告进度。

class ProgressReporter
{
    public:
    virtual ~ProgressReporter() = 0;
    virtual void notifyProgressChanged(void* source, int progressValue) = 0;
}
class Algo
{
    private:
    ProgressReporter* _userProvidedReporter = NULL;
    public:
    void set_ProgressReporter(ProgressReporter*);   // set accessor
    ProgressReporter* get_ProgressReporter();       // get accessor
    void my_heavy_algorithm(int*, int, ...);        // your algo. implementation fn.
}
void Algo::set_ProgressReporter(ProgressReporter* reporter){
    _userProvidedReporter = reporter;
}
ProgressReporter* Algo::get_ProgressReporter(){
    return _userProvidedReporter;
}
void Algo::my_heavy_algorithm(int * data, int n,...){
    // do stuff
    if(_userProvidedReporter != NULL)
        _userProvidedReporter->notifyProgressChanged((void*)this, currentProgress);
    // do more stuff
    if(_userProvidedReporter != NULL)
       _userProvidedReporter->notifyProgressChanged((void*)this, currentProgress);
    // so on and so forth..
}

当然,上面是一个非常简单的例子。如果你希望你的算法支持并发,你应该同步访问内部用户报告器,你可以考虑为你的算法创建一个基类,并提供具体的派生实现。

STL样式函函数可能会对您有所帮助。这也允许你的算法在没有任何进度指示器的情况下使用。

例如,假设您想给出一个进度百分比指示器。

// disclaimer - I didn't compile this code
class NoProgressFeedback; // see below
void my_heavy_algorithm(int * data, int n, ProgressFeedback giveFeedback = NoProgressFeedback() {
    int percentProgress = 0;
    giveFeedback(percentProgress);
    /* start calculations, do stuff */
    percentProgress++;
    giveFeedback(percentProgress);
    /* continue over and repeat percentProgress updates and giveFeedback calls */
}
/* NoProgressFeedback will do no progress feedback */
class NoProgressFeedback {
public:
    operator()(int percent) {}
}

如果用户代码需要反馈,那么它应该向my_heavy_algorithm函数传递一个不同的进度指示器,它应该像这样:

class GetProgressFeedback {
public:
    void operator()(int percent) { std::cout << "percent advance: " << percent; }
}

看看依赖注入。

可以传递一个实现IProgress接口的对象。NullProgress对象可能只有存根,但对于您不感兴趣监视的对象不起实际作用。

通常的方法是在单独的线程中运行计算繁重的工作,并使用它通过锁来更新内存的一部分。UI线程然后定期从这个内存位置读取,并相应地更新屏幕。

要报告正确的进度,您需要三件事:

  1. 对需要完成的全部工作的估计。
  2. 对到目前为止已经完成的工作的估计。
  3. 时间源。

你还需要一些方法让你的"重数学"函数"报告"。一种方法是在"函数的开始","到目前为止的进度"answers"函数的结束"中调用某种函数。函数的开始也设置了"要做的总工作量"。到目前为止的进度报告了"现在完成了多少",而"功能结束"表示"我完成了"。

在c++类环境中,可以这样做:

class Progress
{
    Progress() { };
    virtual void Start(int todo) = 0;
    virtual void Done(int doneSoFar) = 0;
    virtual void Finish();
};

这提供了一个接口,其他类可以从该接口派生。

当然,你仍然需要找到一个有用的速度来放置你的"Done()"-如果你把它放在一个紧密的循环中太深,它会影响性能,但你需要经常这样做,这样它也会显示一些有用的进步。