快速插入独特的容器

时间:2018-04-24 09:39:40

标签: c++ multithreading containers

我必须在2D矢量容器中存储元素(结构状态),并且每个元素必须是唯一的。

我存储这样的元素:

std::vector<std::vector<std::unique_ptr<State>>> m_container;

我有一个插入功能

bool insert(State && value, std::size_t deepness);

如果值是唯一的或者新的深度小于前一个,那么应该将'value'插入m_container [deepness],在这种情况下我必须删除前一个State(插入返回true)。

我有多个线程同时插入,我已经有了一个实现,但我不确定它是否是最好的,所以我对更好,更快的插入方式或一些改进感兴趣。

我的实现时间相当长,因此我尝试将其缩小,同时保持其背后的逻辑。

除了容器我有多图:

std::multimap<std::size_t, std::pair<std::size_t, std::size_t>> m_multimap;

key:状态的哈希

pair_1:深度

pair_2:状态在m_container中的位置[deepness]

我有一个struct Temp的lockless_queue(lockless_queue m_queue)我首先插入到容器中。

template<typename T>
class lockless_queue {
public:
    // storeing the elements
    struct node;
    struct node_ptr;

    // insert element
    template<typename... Args>
    void produce(Args&&... args);
    void produce(T && data);
    void produce(const T & data);

    // consume all elements form queue
    node_ptr consume_all();

    // queue is not empty
    operator bool() const;
};

struct Temp {
    std::unique_ptr<State> value;
    std::size_t hash;
    std::size_t deepness;
    bool exist = false;

    Temp(State * v, std::size_t hash, std::size_t deepness, bool exist);
    Temp(State && v, std::size_t deepness);

    Temp move() {
        return Temp(value.release(), hash, deepness, exist);
    }

    bool is_equal(const State & state) const;
    bool is_equal(State * state) const;
    bool is_equal(const Temp & other) const;
    bool is_equal(Temp * other) const;

    void swap(State && v, std::size_t d) {
        deepness = d;
        value.reset(new State(std::move(v)));
    }
};

以下函数是insert函数,它插入locless_queue

bool pre_emplace(State && value, std::size_t deepness) {
    Temp temp(std::move(value), deepness);
    const auto range = m_multimap.equal_range(temp.hash);
    if (range.first == range.second) {
        m_queue.produce(std::move(temp));
        return true;
    } else {
        const auto & container = m_container;
        const auto it = std::find_if(range.first, range.second, [&temp, &container](const auto & iter) {
            return temp.is_equal(container[iter.second.first][iter.second.second].get());
        });
        if (it == range.second || deepness < it->second.first) {
            temp.exist = true;
            m_queue.produce(std::move(temp));
            return true;
        }
    }
    return false;
}

(某些情况下,返回true无效,因为队列不是唯一但不是问题,我只使用返回值来估计iserted元素的数量)

此函数将队列中的元素消耗为临时mulimap of hash和Temp

void m_finalize_cycle(std::multimap<std::size_t, Temp> & multimap) {
    auto head = m_queue.consume_all();
    auto node = head.ptr;
    while (node != nullptr) {
        if (node->data.value == false) { node = node->next;  continue; }
        auto & temp = node->data;
        const auto range = multimap.equal_range(temp.hash);
        if (range.first == range.second) {
            multimap.emplace(std::make_pair(temp.hash, temp.move()));
        } else {
            const auto it = std::find_if(range.first, range.second, [&temp](const auto & pair) {
                return temp.is_equal(pair.second.value.get());
            });
            if (it == range.second) {
                multimap.emplace_hint(range.first, std::make_pair(temp.hash, temp.move()));
            } else if (temp.deepness < it->second.deepness) {
                it->second.value.reset(temp.value.release());
                it->second.deepness = temp.deepness;
            }
        }
        node = node->next;
    }
}

并且此函数将前一个mulimep中的所有Temp值加载到m_container

void m_finalize_write(std::multimap<std::size_t, Temp> & multimap) {
    for (auto &[hash, temp] : multimap) {
        if (temp.exist) {
            const auto range = m_multimap.equal_range(temp.hash);
            auto & container = m_container;
            const auto it = std::find_if(range.first, range.second, [&temp, &container](const auto & iter) {
                return temp.is_equal(container[iter.second.first][iter.second.second].get());
            });
            if (it != range.second) {
                m_container.at(it->second.first).at(it->second.second).reset(nullptr);
                m_multimap.erase(it);
            }
        } else {
        }
        // extend m_container
        extend_if_needed(temp.deepness);
        m_container.at(temp.deepness).push_back(std::move(std::unique_ptr<State>(temp.value.release())));
        m_multimap.emplace(hash, std::make_pair(temp.deepness, m_container[temp.deepness].size() - 1));
    }
}

当我插入元素时,我每10微秒运行一次m_finalize_cycle,然后如果我完成插入操作,则调用m_finalize_write。

这个实现对我来说很好,但不幸的是,它是我代码中最慢的一部分,所以我对更好的方法感兴趣。

0 个答案:

没有答案