观察到,在下面的rcpp函数中,以某种方式使用type == 0(使用std :: unordered_map而不是std :: map)运行时,运行时间呈非线性增长。
// [[Rcpp::export]]
void cpp_test1(int a, int b, int type)
{
if (type==0)
{
std::unordered_map<int, std::unordered_map<int, NumericVector>> exposure_by_date_name;
for (int i=0; i < a; ++i)
{
for (int j=0; j < b; ++j)
{
exposure_by_date_name[i][j] = NumericVector(68);
}
}
Rcpp::Rcout << "done work " << std::endl;
} else {
std::map<int, std::map<int, NumericVector>> exposure_by_date_name;
for (int i=0; i < a; ++i)
{
for (int j=0; j < b; ++j)
{
exposure_by_date_name[i][j] = NumericVector(68);
}
}
Rcpp::Rcout << "done work " << std::endl;
}
return;
}
这是我捕获system.time捕获的运行时间以及计时结果的方法:
for (type in c(0, 1))
{
for (n in c(10, 50, 100, 200, 500, 1000))
{
this_result = system.time(cpp_test1(100, n, type))
this_result$type = type
this_result$n = n
result = rbind(result, this_result)
print(result)
}
}
print(result)
user.self sys.self elapsed user.child sys.child type n
0.004 0 0.006 0 0 0 10
0.152 0 0.151 0 0 0 50
0.616 0 0.617 0 0 0 100
2.624 0.008 2.631 0 0 0 200
17.828 0.004 17.836 0 0 0 500
58.844 0.06 58.907 0 0 0 1000
0.008 0 0.009 0 0 1 10
0.004 0 0.003 0 0 1 50
0.008 0 0.006 0 0 1 100
0.012 0 0.013 0 0 1 200
0.024 0 0.024 0 0 1 500
0.052 0 0.049 0 0 1 1000
我还注意到,似乎没有花费很多时间来填充地图结构,“完成的工作”打印输出很快就会被打印出,并且大部分时间都花在了某种清理上
是否有人对使用unordered_map时清理工作的漫长等待时间有所了解?
答案 0 :(得分:1)
记录我的发现的部分答案:
-O2
重现g ++ 6.2版和clang ++ 3.8版的问题。std::unordered_map
和Rcpp::NumericVector
或Rcpp::IntegerVector
的组合中发生。std::map
或boost::unordered_map
代替std::unordered_map
消除了此问题。就像使用std::vector<double>
而不是Rcpp::NumericVector
一样。测试代码:
#include <Rcpp.h>
// [[Rcpp::plugins(cpp11)]]
// [[Rcpp::depends(BH)]]
#include <boost/unordered_map.hpp>
template<typename T, typename V>
void map_test(int a, int b) {
T exposure_by_date_name;
for (int i=0; i < a; ++i)
{
for (int j=0; j < b; ++j)
{
exposure_by_date_name[i][j] = V(68);
}
}
Rcpp::Rcout << "done work" << std::endl;
}
// [[Rcpp::export]]
void cpp_test2(int a, int b, int type) {
if (type == 0) {
map_test<std::unordered_map<int, std::unordered_map<int, Rcpp::NumericVector>>, Rcpp::NumericVector>(a, b);
} else if (type == 1) {
map_test<std::map<int, std::map<int, Rcpp::NumericVector>>, Rcpp::NumericVector>(a, b);
} else if (type == 2) {
map_test<std::unordered_map<int, std::unordered_map<int, std::vector<double>>>, std::vector<double>>(a, b);
} else if (type == 3) {
map_test<boost::unordered_map<int, boost::unordered_map<int, Rcpp::NumericVector>>, Rcpp::NumericVector>(a, b);
} else if (type == 4) {
map_test<std::unordered_map<int, std::unordered_map<int, Rcpp::IntegerVector>>, Rcpp::IntegerVector>(a, b);
}
Rcpp::Rcout << "function done" << std::endl;
}
/*** R
result = vector(mode = "list")
for (type in c(0, 1, 2, 3, 4))
{
for (n in c(10, 50, 100, 200, 500))
{
this_result = system.time(cpp_test2(100, n, type))
this_result$type = type
this_result$n = n
result = rbind(result, this_result)
print(result)
}
}
print(result)
*/
结果:
user.self sys.self elapsed user.child sys.child type n
this_result 0.004 0 0.003 0 0 0 10
this_result 0.096 0 0.097 0 0 0 50
this_result 0.444 0 0.443 0 0 0 100
this_result 1.572 0.004 1.574 0 0 0 200
this_result 18.9 0 18.899 0 0 0 500
this_result 0.004 0 0.002 0 0 1 10
this_result 0.004 0 0.004 0 0 1 50
this_result 0.004 0 0.006 0 0 1 100
this_result 0.008 0 0.009 0 0 1 200
this_result 0.028 0 0.026 0 0 1 500
this_result 0.004 0 0.001 0 0 2 10
this_result 0.004 0 0.002 0 0 2 50
this_result 0.004 0 0.004 0 0 2 100
this_result 0.008 0 0.007 0 0 2 200
this_result 0.02 0 0.018 0 0 2 500
this_result 0.004 0 0.001 0 0 3 10
this_result 0 0 0.002 0 0 3 50
this_result 0.004 0 0.004 0 0 3 100
this_result 0.008 0 0.008 0 0 3 200
this_result 0.02 0 0.022 0 0 3 500
this_result 0.004 0 0.003 0 0 4 10
this_result 0.096 0 0.093 0 0 4 50
this_result 0.376 0 0.376 0 0 4 100
this_result 1.508 0 1.508 0 0 4 200
this_result 18.896 0.024 18.916 0 0 4 500