Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/74.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
通过C+将对象写入R中的磁盘+;vs.fst 我受到了 FST 包的启发,尝试编写一个C++函数,以便快速地将R中的一些数据结构串行化到磁盘。p>_C++_R_Rcpp - Fatal编程技术网

通过C+将对象写入R中的磁盘+;vs.fst 我受到了 FST 包的启发,尝试编写一个C++函数,以便快速地将R中的一些数据结构串行化到磁盘。p>

通过C+将对象写入R中的磁盘+;vs.fst 我受到了 FST 包的启发,尝试编写一个C++函数,以便快速地将R中的一些数据结构串行化到磁盘。p>,c++,r,rcpp,C++,R,Rcpp,但即使在非常简单的对象上,我也很难达到相同的写入速度。下面的代码是一个将大型1GB向量写入磁盘的简单示例 使用自定义C++代码,实现了135 Mb/s的写入速度,这是CrystalBench根据磁盘的限制。p> 在相同的数据上,write_fst实现了223 MB/s的写入速度,这似乎是不可能的,因为我的磁盘不能写那么快。(注意,我使用的是fst::threads\u fst(1)和compress=0设置,并且文件具有相同的数据大小。) 我错过了什么 我怎样才能让C++函数更快地写入磁盘?<

但即使在非常简单的对象上,我也很难达到相同的写入速度。下面的代码是一个将大型1GB向量写入磁盘的简单示例

使用自定义C++代码,实现了135 Mb/s的写入速度,这是CrystalBench根据磁盘的限制。p> 在相同的数据上,

write_fst
实现了223 MB/s的写入速度,这似乎是不可能的,因为我的磁盘不能写那么快。(注意,我使用的是
fst::threads\u fst(1)
compress=0
设置,并且文件具有相同的数据大小。)

我错过了什么

<>我怎样才能让C++函数更快地写入磁盘?< /P> C++代码:

#include <Rcpp.h>
#include <fstream>
#include <cstring>
#include <iostream>

// [[Rcpp::plugins(cpp11)]]

using namespace Rcpp;

// [[Rcpp::export]]
void test(SEXP x) {
  char* d = reinterpret_cast<char*>(REAL(x));
  long dl = Rf_xlength(x) * 8;
  std::ofstream OutFile;
  OutFile.open("/tmp/test.raw", std::ios::out | std::ios::binary);
  OutFile.write(d, dl);
  OutFile.close();
}
#包括
#包括
#包括
#包括
//[[Rcpp::插件(cpp11)]]
使用名称空间Rcpp;
//[[Rcpp::导出]]
空隙试验(SEXP x){
char*d=reinterpret_cast(实(x));
长dl=射频长度(x)*8;
std::出流管;
OutFile.open(“/tmp/test.raw”,std::ios::out | std::ios::binary);
输出文件写入(d,dl);
OutFile.close();
}
R代码:

library(microbenchmark)
library(Rcpp)
library(dplyr)
library(fst)
fst::threads_fst(1)

sourceCpp("test.cpp")

x <- runif(134217728) # 1 gigabyte
df <- data.frame(x)

microbenchmark(test(x), write_fst(df, "/tmp/test.fst", compress=0), times=3)
Unit: seconds
                                         expr      min       lq     mean   median       uq      max neval
                                      test(x) 6.549581 7.262408 7.559021 7.975235 8.063740 8.152246     3
 write_fst(df, "/tmp/test.fst", compress = 0) 4.548579 4.570346 4.592398 4.592114 4.614307 4.636501     3

file.info("/tmp/test.fst")$size/1e6
# [1] 1073.742

file.info("/tmp/test.raw")$size/1e6
# [1] 1073.742
库(微基准)
图书馆(Rcpp)
图书馆(dplyr)
图书馆(fst)
fst::线程\u fst(1)
sourceCpp(“test.cpp”)

x对SSD的读写性能进行基准测试是一项棘手的工作,很难做到正确。有许多影响需要考虑

例如,许多SSD使用技术(智能地)加速数据速度,如DRAM缓存。这些技术可以提高您的写入速度,特别是在相同数据集多次写入磁盘的情况下,如您的示例所示。为了避免这种影响,基准测试的每次迭代都应该向磁盘写入一个唯一的数据集

写入和读取操作的块大小也很重要:SSD的默认物理扇区大小为4KB。写入较小的数据块会影响性能,但使用
fst
我发现,由于CPU缓存效应,写入大于几MB的数据块也会降低性能。因为
fst
以相对较小的块将数据写入磁盘,所以它通常比在单个大块中写入数据的替代方法要快

为了便于按块写入SSD,您可以修改代码:

Rcpp::cppFunction('
#包括
#包括
#包括
#定义块大小262144//2^18字节/块
长测试块(SEXP x,Rcpp::字符串路径){
char*d=reinterpret_cast(实(x));
std::出流管;
open(path.get_cstring(),std::ios::out | std::ios::binary);
长dl=射频长度(x)*8;
块的长nr=dl/块大小;
对于(长块\u nr=0;块\u nr<块中的块;块\u nr++){
输出文件写入(&d[block\u nr*BLOCKSIZE],BLOCKSIZE);
}
剩余长_字节=dl%块大小;
outfile.write(&d[n个\u块*块大小],剩余的\u字节);
outfile.close();
返回dl;
}
')
现在,我们可以在单个基准中比较方法
test
test\u blocks
fst::write\u fst

x expr最小lq平均值
#>测试(x,“测试箱”)1.473615 1.506019 1.590430
#>测试块(x,“测试箱”)1.018082 1.062673 1.134956
#>fst::write_fst(df,“test.fst”,compress=0)1.127446 1.144039 1.249864
#>中位数uq max neval
#>  1.600055 1.635883 1.765512    10
#>  1.131631 1.204373 1.264220    10
#>  1.261269 1.327304 1.343248    10
如您所见,修改后的方法
test_blocks
比原始方法快约40%,甚至比
fst
包快一点。这是意料之中的,因为
fst
在存储列和表信息(可能的)属性、哈希和压缩信息方面有一些开销


请注意,在我的系统上,
fst
和您最初的
测试方法之间的差异要小得多,这再次显示了使用基准优化系统的挑战。

谢谢!太棒了。因此,通过在较小的块中写入,部分输出由操作系统保存在缓存中。我发现在你的包里,你用了16KB?你认为这是最安全的区块大小吗?@thc:谢谢!是的,
fst
格式将数据组织在16 kB的块中,这些块是压缩和哈希的基本元素。这种小数据块大小用于促进随机访问(也用于压缩数据)。此外,16 kB非常适合大多数现代CPU的L1 CPU缓存,因此有助于提高数据处理速度(压缩/哈希)。然后,组合多个16 kB的块并将其作为单个块写入磁盘,以进一步优化IO速度。为每种列类型分别选择了用于这些块的16 kB块的最佳数量。@thc:对于您的用例,可能最好使用不同的块大小(示例代码中的标识符块大小)进行一些测试,然后看看会发生什么:-)