我正在实现一些深度学习神经网络,Matlab 中的现有代码通常只是打印到控制台,这样用户就有了进展的想法。
当我为 C++ 进行设计并将算法的核心部分放入我不想将内容打印到控制台的单独函数中时,是否有方法或设计原则可以让使用该算法的用户选择获得某种进度指示?
是否可以让可选参数成为人们可以挂钩的函数指针,或者我将如何做到这一点?
void my_heavy_algorithm(int * data, int n,...);
我正在实现一些深度学习神经网络,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 线程然后定期从这个内存位置读取并相应地更新屏幕。
要报告正确的进度,您需要三件事:
你还需要一些方法让你的“重数学”函数“报告”。一种方法是在“函数开始”、“到目前为止的进度”和“函数结束”中调用某种函数。函数的开始也设置了“要做的工作总量”。迄今为止的进展报告“现在完成了多少”,“功能结束”表示“我完成了”。
在 C++ 类环境中,可以这样做:
class Progress
{
Progress() { };
virtual void Start(int todo) = 0;
virtual void Done(int doneSoFar) = 0;
virtual void Finish();
};
这提供了一个接口,其他类可以从中派生。
当然,你仍然需要找到一个有用的速度来放置你的“Done()”——如果你把它放在某个紧密的循环中太深,它会影响性能,但你需要经常这样做,以显示一些有用的进步也。