C++线程创建大开销

标签 c++ multithreading

我有以下代码,这让我很困惑:

float OverlapRate(cv::Mat& model, cv::Mat& img) {
    if ((model.rows!=img.rows)||(model.cols!=img.cols)) {
        return 0;
    }

    cv::Mat bgr[3];
    cv::split(img, bgr);

    int counter = 0;
    float b_average = 0, g_average = 0, r_average = 0;
    for (int i = 0; i < model.rows; i++) {
        for (int j = 0; j < model.cols; j++) {
            if((model.at<uchar>(i,j)==255)){
                counter++;
                b_average += bgr[0].at<uchar>(i, j);
                g_average += bgr[1].at<uchar>(i, j);
                r_average += bgr[2].at<uchar>(i, j);
            }
        }
    }

    b_average = b_average / counter;
    g_average = g_average / counter;
    r_average = r_average / counter;

    counter = 0;
    float b_stde = 0, g_stde = 0, r_stde = 0;
    for (int i = 0; i < model.rows; i++) {
        for (int j = 0; j < model.cols; j++) {
            if((model.at<uchar>(i,j)==255)){
                counter++;
                b_stde += std::pow((bgr[0].at<uchar>(i, j) - b_average), 2); 
                g_stde += std::pow((bgr[1].at<uchar>(i, j) - g_average), 2); 
                r_stde += std::pow((bgr[2].at<uchar>(i, j) - r_average), 2);                 
            }
        }
    }

    b_stde = std::sqrt(b_stde / counter);
    g_stde = std::sqrt(g_stde / counter);
    r_stde = std::sqrt(r_stde / counter);

    return (b_stde + g_stde + r_stde) / 3;
}


void work(cv::Mat& model, cv::Mat& img, int index, std::map<int, float>& results){
    results[index] = OverlapRate(model, img);
}

int OCR(cv::Mat& a, std::map<int,cv::Mat>& b, const std::vector<int>& possible_values)
{
        int recog_value = -1;
        clock_t start = clock(); 

        std::thread threads[10];
        std::map<int, float> results;
        for(int i=0; i<10; i++)
        {
            threads[i] = std::thread(work, std::ref(b[i]), std::ref(a), i, std::ref(results));
        }

        for(int i=0; i<10; i++)
            threads[i].join();


        float min_score = 1000;
        int min_index = -1;
        for(auto& it:results)
        {
            if (it.second < min_score) {
                min_score = it.second;
                min_index = it.first;
            }
        }

        clock_t end = clock();
        clock_t t = end - start;
        printf ("It took me %d clicks (%f seconds) .\n",t,((float)t)/CLOCKS_PER_SEC);

        recog_value = min_index;
}

以上代码所做的只是简单的光学字符识别。我有一个光学字符作为输入,并将其与 0 - 9 十个标准字符模型进行比较,以获得最相似的一个,然后输出识别值。

当我不使用同时运行的十个线程执行上面的代码时,时间是 7ms。但是,当我使用 10 个线程时,单个光学字符识别的时间下降到 1 或 2 秒。

这是什么原因??调试信息告诉线程创建很耗时,就是这段代码:

threads[i] = std::thread(work, std::ref(b[i]), std::ref(a), i, std::ref(results));

为什么?谢谢。

最佳答案

运行多线程只在两种情况下有用:你有多个硬件核心(所以线程可以同时运行)或者每个线程都在等待 IO(所以一个线程可以运行而另一个线程正在等待 IO,比如磁盘负载或网络传输)。

您的代码不受 IO 限制,所以我希望您有 10 个内核来运行您的代码。如果你没有 10 个核心,那么每个线程都将争夺稀缺资源,而所有资源中最稀缺的是 L1 缓存空间。如果所有 10 个线程都在争夺 1 个或 2 个内核及其缓存空间,那么缓存将“抖动”并使您的性能降低 10-100 倍。

尝试对您的代码进行 10 次不同的基准测试,使用 N=1 到 10 个线程,看看它的性能如何。

(有多个线程的另一个原因是当内核支持超线程时。操作系统将“假装”1 个内核有 2 个虚拟处理器,但这样你就不会获得 2 倍的性能。你得到介于 1 倍和 2 倍之间。但为了获得这种部分提升,你必须在每个内核上运行 2 个线程)

关于C++线程创建大开销,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40013721/

相关文章:

c++ - 分配动态分配的指针数组

c++ - 在 std::map 中使用(数学) vector

c++ - 在没有同步机制的情况下,不同线程同时读取单个 c++ std::map 对象是否安全?

java - 等同于 AsyncTask 的 BlackBerry 类?

c# - 如何在 C# 中使用多线程时循环列表

c++ - Qt中连接不同类的信号槽

c++ - 在 autotools 项目中包含一个(仅 header )库

c# - 在新线程上使用 ObservableCollection

单线程的 Java 同步方法

c++ - 字典式查找对应于一小组值的数百万个键?