我想通过使用move而不是copy来提高以下代码中PickPotatoes的性能,但是我不知道如何使用insertboost::variant来做到这一点。在我的实际用例中,由于复制速度较慢,解析数据大约需要75%的时间,而PickPotatoes的真实版本大约需要25%的时间。通过改善PickPotatoes,我应该能够解决这个问题。是否可以将某些内容从boost::variant中移出并改善PickPotatoes

#include <map>
#include "boost/variant.hpp"
#include <string>
#include <vector>
#include <functional>
struct tuber
{
    int z;
    std::vector<double> r;
};

int getZ(const tuber& t)
{
    return t.z;
}

boost::variant<std::string, tuber> GrowPotato()
{
    int z = std::rand() / (RAND_MAX / 10);
    if (z < 2)
    {
        return "BAD POTATO";
    }
    else
    {
        tuber ret;
        ret.z = z;
        ret.r.resize(10000);
        for (int i = 0;i < 10000;++i)
        {
            ret.r[i] = std::rand() / (RAND_MAX / 50);
        }
        return ret;
    }
}



std::vector<boost::variant<std::string,tuber>> GrowPotatoes(int n)
{

    std::vector<boost::variant<std::string, tuber>> ret;
    ret.resize(n);
    for (int i = 0; i < n; ++i)
    {
        ret[i] = GrowPotato();
    }

    return ret;
}

//could make this more efficient.
std::pair<std::vector<std::string>,std::multimap<int, tuber>> PickPotatoes(std::vector <boost::variant<std::string, tuber>> result)
{
    std::pair<std::vector<std::string>,std::multimap<int,tuber>> ret;
    int numTypTwo = 0;
    for (const auto& item : result)
    {
        numTypTwo += item.which();
    }
    ret.first.resize(result.size() - numTypTwo);
    int fstSpot = 0;
    for (int i = 0; i < result.size();++i)
    {
        if (result[i].which())
        {
            ret.second.insert(std::pair<int, tuber>(getZ(boost::get<tuber>(result[i])), boost::get<tuber>(result[i])));
        }
        else
        {
            ret.first[fstSpot++] = std::move(boost::get<std::string>(result[i]));
        }
    }
    return ret;
}
int main()
{
    std::srand(0);
    std::vector<boost::variant<std::string, tuber>>  q= GrowPotatoes(5000);
    std::pair<std::vector<std::string>, std::multimap<int, tuber>> z = PickPotatoes(q);
    return 0;
}

最佳答案

最简单的方法就是移动参数值:

std::pair<std::vector<std::string>, std::multimap<int, tuber>> z = PickPotatoes(std::move(q));

确实,它赢得了14%的性能,大致按我的基准。其余的内容很大程度上取决于其含义以及如何使用。

专注于减少分配(如果可以,请使用非基于节点的容器,例如boost::flat_multimap,显式排序,使用string_view,解析为所需的数据结构而不是中间数据)。

奖金

我能够使用以下方法剃掉约30%的毛发:
std::pair<std::vector<std::string>, std::multimap<int, tuber> >
PickPotatoes(std::vector<boost::variant<std::string, tuber> >&& result) {

    std::pair<std::vector<std::string>, std::multimap<int, tuber> > ret;

    ret.first.reserve(result.size());

    struct Vis {
        using result_type = void;

        void operator()(std::string& s) const {
            first.emplace_back(std::move(s));
        }
        void operator()(tuber& tbr) const {
            second.emplace(tbr.z, std::move(tbr));
        }

        std::vector<std::string>& first;
        std::multimap<int, tuber>& second;
    } visitor { ret.first, ret.second };

    for (auto& element : result) {
        boost::apply_visitor(visitor, element);
    }

    return ret;
}

使用emplace,避免重复get<>,避免循环获取first大小等。

10-08 08:56