您正在执行大量独立集成。您可以通过同时在单独的内核上执行这些集成来加快速度(如果您有可用的多核处理器)。问题是 R 默认以单线程方式执行其计算。但是,有许多可用的包允许多线程支持。我最近在这里和这里回答了一些类似的问题,并提供了一些关于相关包和功能的附加信息。
此外,正如@Mike Dunlavey 已经提到的,您应该避免对不符合您的标准的t
和的值执行集成。d
(您当前正在对这些值执行不需要的函数评估,然后用 0 覆盖结果)。
我在下面添加了一个可能的改进。请注意,您必须创建一个包含您的函数的单独文件,G
以便在集群节点上对其进行评估。在下面的代码中,假设该文件被调用functionG.R
片段:
library(doParallel)
F4 <- function(t,d) {
results = vector(mode="numeric",max(length=length(t),length(d))) # Zero vector
logicalVector <- ((d > 0) & (t > TMin))
relevantT <- t[logicalVector]
relevantD <- d[logicalVector] # when d is single element, NA values created
if(length(relevantT) > 1 | length(relevantD) > 1)
{
if(length(d)==1) # d is only one element instead of vector --> replicate it
relevantD <- rep(d,length(relevantT))
if(length(t)==1) # t is only one element instead of vector --> replicate it
relevantT <- rep(t,length(relevantD))
cl <- makeCluster(detectCores());
registerDoParallel(cl)
clusterEvalQ(cl,eval(parse("functionG.R")))
integrationResults <- foreach(i=1:length(relevantT),.combine="c") %dopar%
{
integrate(G,lower=0,upper=relevantT[i],relevantT[i],relevantD[i])$value;
}
stopCluster(cl)
results[logicalVector] <- integrationResults
}
else if(length(relevantT==1)) # Cluster overhead not needd
{
results[logicalVector] = integrate(G,lower=0,upper=relevantT,relevantT,relevantD)$value;
}
return(results)
}
我的 CPU 包含 6 个启用超线程的物理内核 (x2)。这些是结果:
> t = -5000:20000
> d = -5000:20000
>
> start = Sys.time()
> testF3 = F3(t,d)
> timeNeededF3 = Sys.time()-start
>
> start = Sys.time()
> testF4 = F4(t,d)
> timeNeededF4 = Sys.time()-start;
> timeNeededF3
Time difference of 3.452825 mins
> timeNeededF4
Time difference of 29.52558 secs
> identical(testF3,testF4)
[1] TRUE
运行此代码时,内核似乎一直在使用。但是,您可以通过在内核周围更有效地预拆分数据来进一步优化此代码,然后在单独的内核上使用应用类型函数。
如果需要更多优化,您还可以更深入地了解该integrate
功能。您可以通过允许不太严格的数值近似来调整设置并获得性能提升。作为替代方案,您可以实现自己的简单版本的自适应辛普森正交并使用离散步长。很可能您可以获得像这样的大量性能提升(如果您能够/愿意在近似值中允许更多错误)。
编辑:
更新代码以使其适用于所有场景:d
和/或t
有效/无效数字或向量
回复评论
@mawir:你是对的。ifelse(test, yes, no)
将为yes
test 计算结果的行返回相应的值TRUE
,它将返回计算结果为的行的相应no
值。但是,它首先必须评估您的表达式才能创建. 这段代码演示了这一点:test
FALSE
yes
yes
length(test)
> t = -5000:5
> d = -5000:5
>
> start = Sys.time()
> testF1 = F(t,d)
> timeNeededF1 = Sys.time()-start
> timeNeededF1
Time difference of 43.31346 secs
>
> start = Sys.time()
> testF4 = F4(t,d)
> timeNeededF4 = Sys.time()-start
> timeNeededF4
Time difference of 2.284134 secs
t
在这种情况下,只有 和 的最后 5 个值d
是相关的。但是,在F1
函数内部,为了创建向量,首先ifelse
评估mapply
所有d
和值。这就是函数执行需要这么长时间的原因。接下来,它选择满足条件的元素,否则为 0。该功能可解决此问题。t
yes
F4
此外,您说您在t
和d
是非向量的情况下获得加速。但是,在这种情况下,没有使用并行化。t
您通常应该在其中一个或两个/d
是向量的情况下获得最大加速。
另一个编辑,以回应 Roland 的评论:如果您不想创建单独的函数文件,您可能会clusterEvalQ(cl,eval(parse("functionG.R")))
替换为。clusterExport(cl,"G")