为什么并行任务管理这么慢?

时间:2019-02-10 20:39:26

标签: c++ multithreading performance c++11

出于下面解释的原因,我已经开始研究创建和运行线程所花费的时间。我这样做的方法是,我发现10个线程大约要花费26 ms的时间,这比原先的时间要长得多-至少根据我的理解。

简短背景:

我正在开发使用寻路的游戏。添加更多实体后,有必要使该过程并行化。

我希望它具有尽可能高的可读性,因此我创建了一个 ParallelTask​​ 类,该类包含一个线程 std :: function (应由踏步执行),互斥体以保护某些写操作,并且布尔完成,一旦线程执行完毕,该布尔值将设置为true。 >

我是多线程的新手,所以我不知道这是不是一个好方法,但总的来说,我一直感到困惑,为什么执行时间这么长。

我已经写了下面的代码来找出问题所在。

int main()
{

    std::map<int, std::unique_ptr<ParallelTask>> parallelTaskDictionary;

    auto start = std::chrono::system_clock::now();

    for (size_t i = 0; i < 10; i++)
    {
         parallelTaskDictionary.emplace(i, std::make_unique<ParallelTask>());
         parallelTaskDictionary[i]->Execute();
    }

    auto end = std::chrono::system_clock::now();
    auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
    std::cout << elapsed.count() << std::endl;

    parallelTaskDictionary.clear();

    return 0;
}


class ParallelTask
{
public:

    ParallelTask();
    // Join the treads
    ~ParallelTask();

public:
    inline std::vector<int> GetPath() const { return path; }
    void Execute();

private:
    std::thread thread;
    mutable std::mutex mutex;

    std::function<void()> threadFunction;
    bool completed;

    std::vector<int> path;
};


ParallelTask::ParallelTask()
{
    threadFunction = [this]() {
        {
            std::lock_guard<std::mutex> lock(mutex);
            this->completed = true;
        }
    };
}

ParallelTask::~ParallelTask()
{
    if (thread.joinable())
    thread.join();
}

void ParallelTask::Execute()
{
    this->completed = false;

    // Launch the thread
    this->thread = std::thread(threadFunction);
}

运行此代码使我的执行时间介于25到26毫秒之间。因为这是要在游戏中使用的,所以它当然是不可接受的。

如前所述,我不明白为什么,特别是因为threadFunction本身确实在字面上指出。如果您想知道,我什至删除了互斥锁,它实际上给了我相同的结果,因此这里肯定还有其他事情发生。 (根据我的研究,创建线程的时间不应超过几微秒,但也许我只是错了^^)

PS:哦,是的,虽然我们在开会,但我仍然不太了解谁应该拥有互斥量。 (是否有一个全局对象或每个对象一个...)?

1 个答案:

答案 0 :(得分:1)

如果只想测量执行时间,我认为应该将now和end语句仅放在工作完成的地方$new_shipping_weight += is_numeric($shipping_weight); 内,如下面的代码所示。

threadFunction

给出输出:

#include <map>
#include <iostream>
#include <memory>
#include <chrono>
#include <vector>
#include <thread>
#include <mutex>
#include <functional>

class ParallelTask
{
public:

    ParallelTask();
    // Join the treads
    ~ParallelTask();

public:
    inline std::vector<int> GetPath() const { return path; }
    void Execute();

private:
    std::thread thread;
    mutable std::mutex mutex;

    std::function<void()> threadFunction;
    bool completed;

    std::vector<int> path;
};


ParallelTask::ParallelTask()
{
    threadFunction = [this]() {
        {
            auto start = std::chrono::system_clock::now();
            std::lock_guard<std::mutex> lock(mutex);
            this->completed = true;
            auto end = std::chrono::system_clock::now();
            auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
            std::cout << "elapsed time" << elapsed.count() << std::endl;
        }
    };
}

ParallelTask::~ParallelTask()
{
    if (thread.joinable())
    thread.join();
}

void ParallelTask::Execute()
{
    this->completed = false;

    // Launch the thread
    this->thread = std::thread(threadFunction);
}


int main()
{

    std::map<int, std::unique_ptr<ParallelTask>> parallelTaskDictionary;


    for (size_t i = 0; i < 10; i++)
    {
         parallelTaskDictionary.emplace(i, std::make_unique<ParallelTask>());
         parallelTaskDictionary[i]->Execute();
    }

    parallelTaskDictionary.clear();

    return 0;
}

因为我们排除了旋转线程所需的时间。

和健全性检查一样,如果您真的想查看实际工作的效果,则可以添加

elapsed time1
elapsed time0
elapsed time0
elapsed time0
elapsed time0
elapsed time0elapsed time
0
elapsed time0
elapsed time0
elapsed time0

转到您的 using namespace std::chrono_literals; std::this_thread::sleep_for(2s); ,使其看起来像这样

threadFunction

输出将是

ParallelTask::ParallelTask()
{
    threadFunction = [this]() {
        {
            auto start = std::chrono::system_clock::now();
            std::lock_guard<std::mutex> lock(mutex);
            this->completed = true;
            using namespace std::chrono_literals;
            std::this_thread::sleep_for(2s);
            auto end = std::chrono::system_clock::now();
            auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
            std::cout << "elapsed time" << elapsed.count() << std::endl;
        }
    };
}