天道酬勤,学无止境

计时函数在C ++中花费多长时间的最佳方法是什么? [复制](What is the best way to time how long functions take in C++? [duplicate])

问题

在C#中,我将启动Stopwatch类以对某些方法花费多长时间进行一些肮脏的计时。

在C ++中,这等效于什么? 有内置的高精度计时器吗?

回答1

以前,我已经为这种情况实现了一个计时器:实际上,我最终得到了一个具有两种不同实现的类,一种用于Windows,一种用于POSIX。

原因是Windows具有QueryPerformanceCounter()函数,该函数使您可以访问非常精确的时钟,这是此类计时的理想选择。

但是在POSIX上不可用,因此我只使用boost.datetime的类来存储开始时间和结束时间,然后根据这些时间来计算持续时间。 它提供了“高分辨率”计时器,但是分辨率是不确定的,并且因平台而异。

回答2

我使用自己的Python time_it函数版本。 此功能的优点在于,它可以重复计算多次以获得有意义的结果。 如果计算速度很快,它将被重复很多次。 最后,您将获得所有重复的平均时间。 它不使用任何非标准功能:

#include <ctime>

double clock_diff_to_sec(long clock_diff)
{
    return double(clock_diff) / CLOCKS_PER_SEC;
}

template<class Proc>
double time_it(Proc proc, int N=1) // returns time in microseconds
{   
    std::clock_t const start = std::clock();
    for(int i = 0; i < N; ++i)
        proc();
    std::clock_t const end = std::clock(); 
    if(clock_diff_to_sec(end - start) < .2) 
        return time_it(proc, N * 5); 
    return clock_diff_to_sec(end - start) * (1e6 / N);
}

下面的示例使用time_it函数来衡量不同的STL容器的性能:

void dummy_op(int i)
{
    if(i == -1)
        std::cout << i << "\n";
}

template<class Container>
void test(Container const & c)
{
    std::for_each(c.begin(), c.end(), &dummy_op);
}

template<class OutIt>
void init(OutIt it)
{
    for(int i = 0; i < 1000; ++i)
        *it = i;
}
    
int main( int argc, char ** argv )
{
    {
        std::vector<int> c;
        init(std::back_inserter(c));
        std::cout << "vector: " 
                  << time_it(boost::bind(&test<std::vector<int> >, c)) << "\n";
    }      
    {
        std::list<int> c;
        init(std::back_inserter(c));
        std::cout << "list: "
                  << time_it(boost::bind(&test<std::list<int> >, c)) << "\n";
    }
    {
        std::deque<int> c;
        init(std::back_inserter(c));
        std::cout << "deque: " 
                  << time_it(boost::bind(&test<std::deque<int> >, c)) << "\n";
    }
    {
        std::set<int> c;
        init(std::inserter(c, c.begin()));
        std::cout << "set: " 
                  << time_it(boost::bind(&test<std::set<int> >, c)) << "\n";
    }
    {
        std::tr1::unordered_set<int> c;
        init(std::inserter(c, c.begin()));
        std::cout << "unordered_set: " 
           << time_it(boost::bind(&test<std::tr1::unordered_set<int> >, c)) << "\n";
    }    
}

如果有人好奇,这是我得到的输出(在发布模式下与VS2008编译):

矢量:8.7168

清单:27.776

双双:91.52

设置:103.04

无序设置:29.76

回答3

我使用boost :: timer来测量操作的持续时间。 它提供了一种非常简单的测量方法,同时又独立于平台。 这是一个例子:

boost::timer myTimer;
doOperation();
std::cout << myTimer.elapsed();

PS为了克服精度误差,最好测量需要几秒钟的操作。 尤其是当您尝试比较几种选择时。 如果您想测量花费很少时间的东西,请尝试将其放入循环中。 例如,将操作运行1000次,然后将总时间除以1000。

回答4

您可以使用ctime库获取时间(以秒为单位)。 以毫秒为单位获取时间是特定于实现的。 这是探讨实现此目的的一些方法的讨论。

另请参阅:如何使用ANSI C来测量以毫秒为单位的时间?

回答5

高精度计时器是特定于平台的,因此C ++标准未指定它,但是有可用的库。 看到这个问题进行讨论。

回答6

我谦虚地提交了自己的微型基准微型库(在Github上)。 它非常简单-与滚动自己的代码相比,它唯一的优势是它已经具有针对Windows和Linux实现的高性能计时器代码,并且可以消除烦人的样板。

只需传入一个函数(或lambda),每次测试运行应调用该函数的次数(默认值:1)以及测试运行的次数(默认值:100)。 返回最快的测试运行(以毫秒为单位):

// Example that times the compare-and-swap atomic operation from C++11
// Sample GCC command: g++ -std=c++11 -DNDEBUG -O3 -lrt main.cpp microbench/systemtime.cpp -o bench
#include "microbench/microbench.h"

#include <cstdio>
#include <atomic>

int main()
{
    std::atomic<int> x(0);
    int y = 0;

    printf("CAS takes %.4fms to execute 100000 iterations\n",
        moodycamel::microbench(
            [&]() { x.compare_exchange_strong(y, 0); },  /* function to benchmark */
            100000, /* iterations per test run */
            100 /* test runs */
        )
    );

    // Result: Clocks in at 1.2ms (12ns per CAS operation) in my environment

    return 0;
}
回答7
#include <time.h>

clock_t start, end;
start = clock();
//Do stuff
end = clock();

printf("Took: %f\n", (float)((end - start) / (float)CLOCKS_PER_SEC));
回答8

这可能是与操作系统有关的问题,而不是语言问题。

如果您使用的是Windows,则可以通过GetTickCount()或GetTickCount64()访问毫秒级的10到16毫秒计时器。 只需在开始时调用一次,在结束时调用一次,然后减去。

如果我没记错的话,那就是我以前使用的方式。 链接页面还有其他选项。

回答9

您可以在本课程中找到有用的信息。

使用RAII惯用语,它会在调用析构函数时打印构造中给出的文本,并用适当的值填充经过的时间占位符。

使用示例:

int main()
{
   trace_elapsed_time t("Elapsed time: %ts.\n");
   usleep(1.005 * 1e6);
} 

输出:

Elapsed time: 1.00509s.
标签

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 如何使用timeit模块(How to use timeit module)
    问题 我明白什么概念timeit做,但我不知道如何实现它在我的代码。 我如何比较两个功能,说insertion_sort和tim_sort ,与timeit ? 回答1 timeit的工作方式是运行一次安装代码,然后重复调用一系列语句。 因此,如果要测试排序,则需要格外小心,以免就地排序的一次通过不会影响已排序数据的下一轮(当然,这会使Timsort真正发光,因为它表现最佳当数据已经部分排序时)。 这是一个如何设置排序测试的示例: >>> import timeit >>> setup = ''' import random random.seed('slartibartfast') s = [random.random() for i in range(1000)] timsort = list.sort ''' >>> print min(timeit.Timer('a=s[:]; timsort(a)', setup=setup).repeat(7, 1000)) 0.334147930145 请注意,这一系列语句在每次通过时都会对未排序的数据进行全新复制。 另外,请注意运行测量套件七次并仅保持最佳时间的计时技术-这确实可以帮助减少由于系统上正在运行其他进程而导致的测量失真。 这些是我正确使用timeit的技巧。 希望这可以帮助 :-) 回答2
  • 大八岁的孩子? [复制](Big-O for Eight Year Olds? [duplicate])
    问题 这个问题已经在这里有了答案: 用英语简单地解释“ Big O”表示法是什么? (42个答案) 3年前关闭。 我想问更多关于这对我的代码意味着什么。 我从数学上理解这些概念,我很难理解它们在概念上的含义。 例如,如果要对一个数据结构执行O(1)操作,我知道它必须执行的操作数量不会增加,因为有更多的项。 O(n)操作意味着您将对每个元素执行一组操作。 有人可以在这里填补空白吗? 就像O(n ^ 2)运算会做什么一样? 如果操作是O(n log(n)),这意味着什么呢? 有人要抽烟写O(x!)吗? 回答1 一种思考的方式是: O(N ^ 2)意味着对于每个元素,您正在与其他所有元素一起做某事,例如比较它们。 冒泡排序就是一个例子。 O(N log N)意味着对于每个元素,您所做的事情仅需要查看元素的logN。 这通常是因为您了解一些有关使您做出有效选择的要素的知识。 最有效的排序就是这种示例,例如合并排序。 O(N!)意味着对N个元素的所有可能排列进行某些操作。 一个旅行推销员就是一个例子,那里有N个! 一种访问节点的方法,而强力解决方案是查看每种可能排列的总成本以找到最佳排列。 回答2 Big-O表示法对您的代码而言,最重要的事情是,当您将其操作的“事物”数量加倍时,它将如何扩展。 这是一个具体的例子: Big-O | computations for 10 things |
  • 将const std :: string&作为参数传递的日子已经过去了吗?(Are the days of passing const std::string & as a parameter over?)
    问题 我听过Herb Sutter最近的一次演讲,他提出通过const &传递std::vector和std::string的原因已基本消失。 他建议现在编写一个如下所示的函数是更可取的: std::string do_something ( std::string inval ) { std::string return_val; // ... do stuff ... return return_val; } 我知道return_val在函数返回时将是一个右值,因此可以使用移动语义返回,这非常便宜。 但是, inval仍然比引用(通常实现为指针)的大小大得多。 这是因为std::string具有各种组件,包括指向堆的指针和用于短字符串优化的成员char[] 。 因此在我看来,通过引用传递仍然是一个好主意。 谁能解释为什么Herb可能会这么说? 回答1 赫伯之所以说他的话,是因为这样的情况。 假设我有A函数B ,该函数调用函数B ,该函数调用函数C A将字符串通过B传递到C A不知道或不在乎C ; A知道B 也就是说, C是B的实现细节。 假设A定义如下: void A() { B("value"); } 如果B和C通过const&接受字符串,则它看起来像这样: void B(const std::string &str) { C(str); } void C(const std
  • 您最有争议的编程观点是什么?(What's your most controversial programming opinion?)
    问题 已锁定。 该问题及其答案被锁定,因为该问题是题外话,但具有历史意义。 它目前不接受新的答案或互动。 这绝对是主观的,但我想避免它引起争论。 我认为如果人们适当地对待它可能是一个有趣的问题。 这个问题的想法来自我对“您讨厌自己喜欢的语言的五件事是什么?”的回答中的评论主题。 问题。 我认为默认情况下应该密封C#中的类-我不会在问题中加入我的推理,但是我可能会写一个更完整的解释作为对此问题的答案。 我对评论中的讨论热度感到惊讶(目前有25条评论)。 那么,您持有哪些有争议的意见? 我宁愿避免那种在没有什么基础的情况下就变得非常虔诚的事情(例如,大括号放置),但是示例可能包括诸如“单元测试实际上并没有非常有用的帮助”或“公共领域真的可以”这样的事情。 重要的是(无论如何对我而言)是您有自己的理由。 请提出您的观点和理由-无论您是否同意,我都会鼓励人们投票支持有争议和有趣的观点。 回答1 那些不会在业余时间编写代码的程序员将永远不会像那些程序员那样优秀。 我认为,即使最聪明,最有才华的人也永远不会成为真正的优秀程序员,除非他们将其视为一项工作。 这意味着他们一边做一些小项目,要么在业余时间就与许多不同的语言和想法混为一谈。 (注意:我并不是说优秀的程序员除了编程之外什么都不做,但是他们比9到5的程序还要多。) 回答2 您应该一直使用的唯一“最佳实践”是“使用您的大脑”。
  • 超越堆栈采样:C ++ Profiler(Beyond Stack Sampling: C++ Profilers)
    问题 黑客的故事 日期是2010年12月2日。 圣诞节前的日子不多了,作为Windows程序员,我几乎遇到了一个主要障碍。 我一直在使用AQTime,尝试过困倦,发亮并且非常困倦,正如我们所说的,VTune正在安装。 我曾尝试使用VS2008 Profiler,但它一直在积极地惩罚着人们,而且常常是愚蠢的。 我使用了随机暂停技术。 我已经检查了呼叫树。 我已经解雇了功能痕迹。 但是令人悲伤的事实是,我正在使用的应用程序超过一百万行代码,可能还有另外一百万行价值的第三方应用程序。 我需要更好的工具。 我已经阅读了其他主题。 我已经尝试了每个主题中列出的每个事件探查器。 仅仅是必须有比这些垃圾和昂贵的选择更好的东西,或者可笑的工作量几乎没有收益。 更复杂的是,我们的代码使用了大量线程,并运行许多Qt Event循环,其中一些非常脆弱,以至于由于定时延迟而在繁重的测试中崩溃。 不要问我为什么我们要运行多个事件循环。 没有人能告诉我。 在Windows环境中,Valgrind还有更多选择吗? 有没有比我已经尝试过的一堆破烂的工具更好的东西了? 是否有任何旨在与Qt集成的东西,也许可以对队列中的事件进行有用的显示? 我尝试过的工具的完整列表,以及在斜体中真正有用的工具: AQTime:很好! 深度递归会遇到一些麻烦,但是在这些情况下,调用图是正确的,并且可以用来消除您可能遇到的任何混乱。
  • 在“ for”循环中加1时格式化背后的技术原因?(Technical reasons behind formatting when incrementing by 1 in a 'for' loop?)
    问题 在整个网络中,代码示例具有for循环,如下所示: for(int i = 0; i < 5; i++) 而我使用以下格式: for(int i = 0; i != 5; ++i) 我这样做是因为我相信它会更有效率,但是在大多数情况下,这真的很重要吗? 回答1 每个人都喜欢他们的微优化,但是就我所知,这并没有什么不同。 我在没有任何花哨的优化的情况下针对英特尔处理器使用g ++编译了这两种变体,结果是 for(int i = 0; i < 5; i++) movl $0, -12(%ebp) jmp L2 L3: leal -12(%ebp), %eax incl (%eax) L2: cmpl $4, -12(%ebp) jle L3 for(int i = 0; i != 5; ++i) movl $0, -12(%ebp) jmp L7 L8: leal -12(%ebp), %eax incl (%eax) L7: cmpl $5, -12(%ebp) jne L8 我认为jle和jne应该在大多数体系结构上转换为同样快速的指令。 因此,为了提高性能,您不应在两者之间进行区分。 总的来说,我同意第一个比较安全,我也认为更常见。 编辑(2年后):由于该线程最近再次引起了很多关注,我想补充一点,通常很难回答这个问题。 C-Standard [PDF
  • 为什么要使用指针? [关闭](Why use pointers? [closed])
    问题 从目前的情况来看,这个问题不适合我们的问答形式。 我们希望答案得到事实,参考或专业知识的支持,但是这个问题可能会引起辩论,争论,民意测验或进一步的讨论。 如果您认为此问题可以解决并且可以重新提出,请访问帮助中心以获取指导。 7年前关闭。 我知道这是一个非常基本的问题,但是在使用高级语言编写了一些项目之后,我才开始进行一些基本的C ++编程。 基本上我有三个问题: 为什么在普通变量上使用指针? 我应该在何时何地使用指针? 如何将指针与数组一起使用? 回答1 为什么在普通变量上使用指针? 简短的答案是:不。 ;-)指针将用于不能使用其他任何东西的地方。 这是因为缺少适当的功能,缺少数据类型或纯粹是出于性能考虑。 下面更多... 我应该在何时何地使用指针? 简短的答案是:无法使用其他任何东西。 在C语言中,您不支持复杂的数据类型,例如字符串。 也没有办法将变量“通过引用”传递给函数。 那是您必须使用指针的地方。 您也可以让他们指向几乎所有内容,链接列表,结构成员等。 但是,我们不要在这里讨论。 如何将指针与数组一起使用? 毫不费力,却很混乱。 ;-)如果我们讨论诸如int和char这样的简单数据类型,则数组和指针之间几乎没有什么区别。 这些声明非常相似(但不相同-例如, sizeof将返回不同的值): char* a = "Hello"; char a[] = "Hello"
  • 重复字符串-Javascript(Repeat String - Javascript)
    问题 返回任意多次重复的字符串的最佳或最简洁的方法是什么? 以下是到目前为止我最好的拍摄: function repeat(s, n){ var a = []; while(a.length < n){ a.push(s); } return a.join(''); } 回答1 好消息! String.prototype.repeat现在是JavaScript的一部分。 "yo".repeat(2); // returns: "yoyo" 除Internet Explorer之外,所有主要浏览器均支持该方法。 有关最新列表,请参见MDN:String.prototype.repeat>浏览器兼容性。 MDN具有不支持浏览器的polyfill。 回答2 给新读者的注意:这个答案是古老的,并且不是很实用-它只是“聪明”,因为它使用Array的东西来完成String的工作。 当我编写“更少的过程”时,我的意思绝对是“更少的代码”,因为正如其他人在随后的答案中指出的那样,它的表现像猪一样。 因此,如果速度对您很重要,请不要使用它。 我直接将此函数放到String对象上。 无需创建数组,填充数组并使用空字符将其连接,只需创建适当长度的数组,然后将其与所需的字符串连接即可。 结果相同,过程更少! String.prototype.repeat = function( num ) {
  • 如何加快我的Perl程序?(How can I speed up my Perl program?)
    问题 这确实是两个问题,但是它们是如此相似,并且为了简单起见,我想将它们放在一起: 首先:在已经建立了Perl项目的情况下,除了普通的代码内优化之外,还有什么不错的方法来加快它的速度? 其次:在Perl中从头开始编写程序时,有什么好的方法可以极大地提高性能? 对于第一个问题,想像一下您已经交付了一个体面的项目,并且需要提高性能,但是您似乎无法通过重构/优化获得太多收益。 在这种情况下,如果不使用C之类的方式重写它,您将如何加速? 除非它们是Perl专用的,否则请远离常规的优化技术。 我早些时候问过有关Python的问题,我认为对其他语言使用Python可能会很好(我特别好奇Perl的psycho和pyrex有必然的推论)。 回答1 请记住优化俱乐部的规则: Optimization Club的第一条规则是,您不进行优化。 Optimization Club的第二条规则是,您必须进行不计量而不进行优化。 如果您的应用程序运行速度快于基础传输协议,则优化已结束。 一次一个因素。 没有marketoid,没有marketroid时间表。 测试将一直进行下去。 如果这是您在Optimization Club的第一个晚上,则必须编写一个测试用例。 因此,假设您实际有工作代码,请在Devel :: NYTProf下运行您的程序。 找到瓶颈。 然后回到这里告诉我们它们是什么。
  • 如何从int转换为char *?(how to convert from int to char*?)
    问题 我知道的唯一方法是: #include <sstream> #include <string.h> using namespace std; int main() { int number=33; stringstream strs; strs << number; string temp_str = strs.str(); char* char_type = (char*) temp_str.c_str(); } 但是,有没有一种方法可以减少打字? 回答1 在C ++ 17中,将std :: to_chars用作: std::array<char, 10> str; std::to_chars(str.data(), str.data() + str.size(), 42); 在C ++ 11中,将std :: to_string用作: std::string s = std::to_string(number); char const *pchar = s.c_str(); //use char const* as target type 在C ++ 03中,除了将const用作:之外,您所做的一切都很好。 char const* pchar = temp_str.c_str(); //dont use cast 回答2 我认为您可以使用sprintf: int
  • 为什么编译器如此愚蠢?(Why are compilers so stupid?)
    问题 我总是想知道为什么编译器无法找出人眼显而易见的简单事物。 他们进行了许多简单的优化,但从未做过任何复杂的事情。 例如,此代码在我的计算机上花费大约6秒钟来打印零值(使用Java 1.6): int x = 0; for (int i = 0; i < 100 * 1000 * 1000 * 1000; ++i) { x += x + x + x + x + x; } System.out.println(x); 显而易见,x永远不会改变,因此无论您多久将其加0,它都将保持为零。 因此,编译器理论上可以将其替换为System.out.println(0)。 甚至更好,这需要23秒: public int slow() { String s = "x"; for (int i = 0; i < 100000; ++i) { s += "x"; } return 10; } 首先,编译器可能会注意到我实际上正在创建一个100000“ x”的字符串,因此它可以自动使用s StringBuilder代替,甚至更好地直接将其替换为结果字符串,因为它始终是相同的。 其次,它不认识到我实际上根本没有使用字符串,因此整个循环可能会被丢弃! 为什么在投入大量精力投入快速编译器之后,它们仍然相对笨拙? 编辑:当然,这些都是愚蠢的示例,永远不要在任何地方使用。 但是
  • C ++:Linux中的计时(使用clock())不同步(由于OpenMP?)(C++: Timing in Linux (using clock()) is out of sync (due to OpenMP?))
    问题 在程序的顶部和结尾,我使用clock()来计算程序需要花费多长时间。 不幸的是,它花费的时间似乎是报告时间的一半。 我用“时间”命令仔细检查了一下。 我的程式报告:45.86秒内完成 时间命令报告:真实0m22.837s用户0m45.735s sys 0m0.152s 用我的手机计时,它完成了23秒(又称“真实”时间)。 “用户”时间是所有线程的总和,这很有意义,因为我使用的是OpenMP。 (您可以在此处阅读有关内容:time(1)输出中的“ real”,“ user”和“ sys”是什么意思?) 那么,为什么clock()在“用户”时间内而不是“真实”时间内报告? 我应该使用其他函数来计算程序运行了多长时间吗? 附带说明一下,Windows的clock()可以按预期工作,并以“实时”报告。 回答1 用户0m45.735s clock() )根据7.27.2.1衡量所使用的进程(尽可能好clock() CPU时间 自实现定义的仅与程序调用相关的时代开始以来,时钟函数就将实现的最佳近似返回到程序所使用的处理器时间。 而不是挂钟时间。 因此, clock()报告的时间接近于user报告的时间,该time报告是正常且符合标准的。 要测量经过的时间,如果可以假设使用POSIX,则使用clock_gettime可能是最好的选择,也可以使用标准函数time()来实现,但粒度不是很细。
  • 常规C ++性能改进技巧[关闭](General C++ Performance Improvement Tips [closed])
    问题 关门了。 这个问题需要更加集中。 它当前不接受答案。 想改善这个问题吗? 更新问题,使其仅通过编辑此帖子即可将重点放在一个问题上。 2年前关闭。 改善这个问题 有人可以给我指出一篇文章,还是在这里写一些有关一些通常有效的C ++编程习惯的提示(没有真正的缺点)并提高性能? 我并不是说编程模式和算法复杂性-我需要一些小事情,例如如何定义函数,要做/避免在循环中做的事情,在栈上分配什么,在堆上分配什么,等等。 这与加快特定软件的速度有关,也不与如何创建干净的软件设计有关,而是与编程习惯有关—如果您始终应用它们,则可以使您的代码更快而不是更慢。 回答1 有效C ++,更有效C ++,有效STL和C ++编码标准中的许多技巧都遵循这条原则。 一个简单的技巧示例:尽可能使用预增量(++ i)而不是后增量(i ++)。 这对于迭代器尤其重要,因为后增量涉及复制迭代器。 您的优化器可能可以撤消此操作,但是编写预增量并不是多余的工作,那么为什么要冒险呢? 回答2 如果我对您的理解正确,那么您会问是要避免过早过时的Pessimization ,这是避免过早的优化的一个很好的补充。 根据我的经验,要避免的第一件事是尽可能不复制大型对象。 这包括: 通过(常量)对函数的引用传递对象在可行的情况下,通过(const)引用返回对象确保在需要时声明引用变量 最后一个项目符号需要一些解释。
  • 是否有任何推荐的Java性能分析教程? [关闭](Any recommended Java profiling tutorial? [closed])
    问题 关闭。 此问题不符合堆栈溢出准则。 它当前不接受答案。 想要改善这个问题吗? 更新问题,使它成为Stack Overflow的主题。 7年前关闭。 改善这个问题 是否有任何推荐的Java应用程序性能分析教程? 我现在在分析时使用JProfiler和Eclipse测试与性能工具平台(TPTP)。 但是,尽管配备了出色的武器,但作为Java概要分析的新手,我仍然缺少指出瓶颈的一般理论和技能。 回答1 概要分析是一门多学科思想的学科。 比较流行的一种是您要进行测量。 也就是说,您尝试查看每个函数需要花费多长时间和/或被调用多少次。 显然,如果一个函数花费很少的时间,那么加快它的收益将不大。 但是,如果要花费很多时间,那么您就必须进行侦探工作才能弄清楚该功能的哪个部分负责该时间。 不要期望函数的时间加起来就是总的时间,因为函数会相互调用,而函数A可能要花费很多时间的原因是它调用函数B也会花费很多时间。 这种方法可能会发现很多问题,但这取决于您是一名优秀的侦探,并且能够清楚地思考各种时间,例如挂钟时间与CPU时间,自拍时间与包含时间。 例如,一个应用程序看起来可能很慢,但是功能时间可能全部报告为接近零。 这可能是由于程序受I / O约束。 如果I / O是您所期望的,那可能很好,但是它可能正在执行一些您不知道的I / O,然后您就可以重新进行侦探工作了。。。。。。。。。。。。。。。。。
  • 我可以编写没有头文件(重复的函数声明)的C ++代码吗?(Can I write C++ code without headers (repetitive function declarations)?)
    问题 有没有什么方法不必两次编写函数声明(标头),而在用C ++编程时仍保持编译时的可伸缩性,调试的清晰度和设计的灵活性? 回答1 使用Lzz。 它只需要一个文件,并为您自动创建一个.h和.cpp,并将所有声明/定义放在正确的位置。 Lzz确实非常强大,可以处理99%的完整C ++语法,包括模板,专业化等,等等。 更新150120: 较新的C ++ '11 / 14语法只能在Lzz函数体内使用。 回答2 当我开始编写C时,我有相同的感觉,因此我也对此进行了研究。 答案是,是的,有可能,没有,您不想这样做。 首先是。 在GCC中,您可以执行以下操作: // foo.cph void foo(); #if __INCLUDE_LEVEL__ == 0 void foo() { printf("Hello World!\n"); } #endif 这具有预期的效果:将标头和源代码组合到一个可以包含和链接的文件中。 然后用no: 仅当编译器有权访问整个源时,此方法才有效。 编写要分发但保持源代码封闭的库时,您不能使用此技巧。 要么分发完整的.cph文件,要么必须编写单独的.h文件以与.lib一起使用。 尽管也许您可以使用宏预处理器自动生成它。 它会变得毛茸茸的。 第二个原因就是您不想要这个,这可能是最好的选择:编译速度。 通常,仅当文件本身更改或包含更改的任何文件时,才需要重新编译C源文件
  • 何时使用内联函数,什么时候不使用内联函数?(When to use inline function and when not to use it?)
    问题 我知道内联是对编译器的提示或请求,其用于避免函数调用的开销。 那么,在什么基础上可以确定某个函数是否适合内联呢? 在这种情况下,应避免内联? 回答1 避免函数调用的代价只是故事的一半。 做: 使用inline而不是#define 非常小的函数非常适合inline :更快的代码和更小的可执行文件(更多的机会保留在代码缓存中) 该函数很小,经常调用 别: 大型函数:导致较大的可执行文件,无论调用开销导致更快的执行速度,都将严重损害性能。 受I / O约束的内联函数该功能很少使用构造函数和析构函数:即使为空,编译器也会为它们生成代码开发库时破坏二进制兼容性: 内联现有功能更改内联函数或使内联函数变为非内联:库的先前版本调用旧的实现 在开发库时,为了使将来的类可扩展,您应该: 即使正文为空,也添加非内联虚拟析构函数使所有构造函数都是非内联的编写复制构造函数和赋值运算符的非内联实现,除非无法通过值复制该类 请记住, inline关键字是对编译器的提示:编译器可以决定不对函数进行内联,并且可以决定对未首先标记为inline的函数进行inline 。 我通常避免将函数inline标记(除了在编写非常小的函数时)。 关于性能,明智的方法是(一如既往)分析应用程序,然后最终inline代表瓶颈的一组功能。 参考: 内联或不内联 [9]内联函数 C ++的策略/二进制兼容性问题第33号
  • 英文对“ Big O”符号的解释是什么?(What is a plain English explanation of “Big O” notation?)
    问题 我希望尽量少用正式的定义和简单的数学方法。 回答1 快速说明,这几乎肯定会使Big O表示法(上限)与Theta表示法“Θ”(两侧界线)混淆。 以我的经验,这实际上是非学术场合中讨论的典型内容。 造成任何混乱,我们深表歉意。 此图可以直观地显示O的复杂性: 我可以为Big-O表示法给出的最简单定义是: Big-O表示法是算法复杂度的相对表示。 该句子中有一些重要的和故意选择的单词: 相对的:您只能将苹果与苹果进行比较。 您无法将进行算术乘法的算法与对整数列表进行排序的算法进行比较。 但是,对两种进行算术运算的算法进行比较(一次乘法,一次加法)将告诉您一些有意义的事情。 表示形式: Big-O(以最简单的形式)将算法之间的比较简化为单个变量。 该变量是根据观察或假设选择的。 例如,排序算法通常基于比较操作进行比较(比较两个节点以确定它们的相对顺序)。 这假定比较是昂贵的。 但是,如果比较便宜但交换费用昂贵怎么办? 它改变了比较; 和复杂性:如果我需要一秒钟来排序10,000个元素,那么我要花多长时间来排序一百万个元素? 在这种情况下,复杂性是相对于其他事物的相对度量。 阅读完其余内容后,请重新阅读以上内容。 我能想到的Big-O最好的例子是算术。 取两个数字(123456和789012)。 我们在学校学到的基本算术运算是: 添加; 减法乘法; 和分配。 这些都是操作或问题。
  • 用于字符串连接的StringBuilder抛出OutOfMemoryException(StringBuilder for string concatenation throws OutOfMemoryException)
    问题 我们通常倾向于遵循上述最佳做法。 看看String vs StringBuilder 但是,即使有足够的可用内存, StringBuilder也会抛出OutOfMemoryException 。 因为它需要“连续的内存块”,所以将引发OOM异常。 一些链接供参考StringBuilder OutOfMemoryException 还有更多..... 你们当中有多少人面对这个问题或意识到这一点,您做了什么来解决呢? 有什么我想念的吗? PS:我不知道这一点。 我已经改过了这个问题。 ***相同的情况也适用于手动串联(我将对此进行验证并更新SO)。 引起我担心的另一件事是系统中有足够的内存。 这就是我在这里提出此问题的原因,以检查是否有人遇到此问题或代码是否存在严重错误。 回答1 您创建的底层字符串也将需要一个连续的内存块,因为它表示为char数组(数组需要连续的内存)。 如果StringBuilder引发OOM异常,那么您将无法没有它来构建基础。 如果创建字符串导致OOM,则您的应用程序中可能存在更严重的问题。 根据说明进行编辑: 在少数情况下,当手动串联成功时,使用StringBuilder构建字符串将失败。 手动串联将使用所需的确切长度,以便组合两个字符串,而StringBuilder具有不同的分配内存的算法。 它更具攻击性,可能会分配比字符串实际所需更多的内存。
  • 每x秒重复执行一个函数的最佳方法是什么?(What is the best way to repeatedly execute a function every x seconds?)
    问题 我想永远每60秒重复执行一次Python中的函数(就像Objective C中的NSTimer一样)。 该代码将作为守护程序运行,实际上就像使用cron每分钟调用python脚本一样,但是不需要用户设置。 在有关使用Python实现的cron的问题中,该解决方案似乎实际上只是将sleep()停留了x秒钟。 我不需要这种高级功能,所以也许这样的事情会起作用 while True: # Code executed here time.sleep(60) 此代码是否存在任何可预见的问题? 回答1 如果您的程序还没有事件循环,请使用sched模块,该模块实现了通用事件调度程序。 import sched, time s = sched.scheduler(time.time, time.sleep) def do_something(sc): print("Doing stuff...") # do your stuff s.enter(60, 1, do_something, (sc,)) s.enter(60, 1, do_something, (s,)) s.run() 如果你已经在使用一个事件循环库像asyncio , trio , tkinter , PyQt5 , gobject , kivy ,和许多其他-使用您现有的事件循环库的方法,只是安排任务,来代替。 回答2
  • 微优化值得吗?(Is micro-optimization worth the time?)
    问题 我是一名PHP开发人员,我一直认为微优化是不值得的。 如果您确实需要这种额外的性能,则可以编写软件以使其在体系结构上更快,或者编写C ++扩展来处理缓慢的任务(或者更好的方法是使用HipHop编译代码)。 但是今天有个同事告诉我 is_array($array) 和 $array === (array) $array 而且我就像“嗯,那确实是没有意义的比较”,但是他不同意我的看法。.他是我们公司中最好的开发人员,并且负责一个每天执行约5000万次SQL查询的网站- - 例如。 因此,我想知道的是:他可能是错的,还是微优化真的值得您花时间和时间? 回答1 当您有证据证明您正在优化瓶颈时,微优化是值得的。 通常这是不值得的-编写尽可能可读的代码,并使用实际的基准来检查性能。 如果发现瓶颈,则对那部分代码进行微优化(随需测量)。 有时,少量的微优化可能会产生巨大的变化。 但是不要对所有代码进行微优化……最终将很难维护,您很可能会发现您错过了真正的瓶颈,或者您的微优化正在损害性能,而不是损害性能。帮助。 回答2 好吧,对于一个很小的数组, $array === (array) $array比is_array($array)快得多。 速度提高了7倍以上。 但是每个呼叫仅约1.0 x 10 ^ -6秒( 0.000001 seconds )。 因此,除非您真的要成千上万次调用它