我必须在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。
这个实现对我来说很好,但不幸的是,它是我代码中最慢的一部分,所以我对更好的方法感兴趣。