在data.table v1.12.0
的变更日志中,我注意到以下内容:
子集,排序和分组现在使用更多的并行性
我测试了是否可以加快分组速度,但是没有成功。我做了几个不同的测试,并且我总是得到相同的结果。分组实际上是并行的吗?也许我没有正确使用线程选项?如您所见,data.table
已使用openmp
进行了编译,否则setDTthread
打印一条消息,告诉用户不支持openmp
。这是我的一项测试的可复制示例。
library(data.table)
n = 5e6
k = 1e4
DT = data.table(x = runif(n), y = runif(n), grp = sample(1:k, n, TRUE))
# Any function not too fast
f = function(x,y) as.list(eigen(cov(cbind(x,y)), only.values = TRUE)$value)
setDTthreads(1)
getDTthreads()
#> [1] 1
system.time(DT[ , f(x,y), by = grp])
#> utilisateur système écoulé
#> 3.365 0.008 3.374
setDTthreads(0)
getDTthreads(T)
#> omp_get_max_threads() = 4
#> omp_get_thread_limit() = 2147483647
#> DTthreads = 0
#> RestoreAfterFork = true
#> [1] 4
system.time(DT[ , f(x,y), by = grp])
#> utilisateur système écoulé
#> 3.324 0.029 3.238
由reprex package(v0.2.1)于2019-01-27创建
答案 0 :(得分:4)
是的,分组在v 1.12.0中是并行的
您的基准测试有点麻烦。如果要隔离分组速度,则需要 fast f(x, y)
。使用示例的基数,但使用一个简单的函数,我们得到:
library(data.table)
packageVersion("data.table")
#> [1] '1.12.0'
n = 5e6
N <- n
k = 1e4
print(getDTthreads())
#> [1] 12
DT = data.table(x = rep_len(runif(n), N),
y = rep_len(runif(n), N),
grp = rep_len(sample(1:k, n, TRUE), N))
bench::system_time(DT[, .(a = 1L), by = "grp"])
#> process real
#> 250.000ms 72.029ms
setDTthreads(1)
bench::system_time(DT[, .(a = 1L), by = "grp"])
#> process real
#> 125.000ms 126.385ms
由reprex package(v0.2.1)于2019-02-01创建
也就是说,在并行情况下,我们的速度稍快一些,但仅增加了约50毫秒,与函数的3 s相比可以忽略不计。
如果我们扩大DT的大小,我们会发现更大的差异:
library(data.table)
packageVersion("data.table")
#> [1] '1.12.0'
n = 5e6
N <- 1e9
k = 1e4
print(getDTthreads())
#> [1] 12
DT = data.table(x = rep_len(runif(n), N),
y = rep_len(runif(n), N),
grp = rep_len(sample(1:k, n, TRUE), N))
bench::system_time(DT[, .(a = 1L), by = "grp"])
#> process real
#> 45.719s 14.485s
setDTthreads(1)
bench::system_time(DT[, .(a = 1L), by = "grp"])
#> process real
#> 24.859s 24.890s
sessioninfo::session_info()
#> - Session info ----------------------------------------------------------
#> setting value
#> version R version 3.5.2 (2018-12-20)
#> os Windows 10 x64
#> system x86_64, mingw32
#> ui RTerm
#> language (EN)
#> collate English_Australia.1252
#> ctype English_Australia.1252
#> tz Australia/Sydney
#> date 2019-02-01
#>
由reprex package(v0.2.1)于2019-02-01创建
答案 1 :(得分:1)
根据我对github存储库中的data.table
问题的探索,这里的答案没有得到任何权威机构(例如data.table
团队的成员)的验证。
从问题#3042开始,我了解sum
和mean
已优化。我们可以对其进行基准测试以验证其正确性:
library(data.table)
n = 1e7 ; k = 1e5
DT = data.table(x = runif(n), y = runif(n), grp = sample(1:k, n, TRUE))
setDTthreads(1)
system.time(DT[ , mean(x), by = grp]) #> 0.8 s
setDTthreads(0)
system.time(DT[ , mean(x), by = grp]) #> 0.4 s
但是在同一期#3042中,马特·道尔(Matt Dowle)写道:
要扩展到其他gforce函数和对任意函数进行分组还有很多工作要做
sritchie73在#3130中写道
这里值得一提的是R函数本质上不是线程安全的,例如因此无法通过Rcpp将它们传递给多线程C ++代码。
因此,看来用户定义函数的并行化并非一件容易的事,data.table
中目前没有实现。