我有一个闪亮的应用程序,它接受用户提供的数据,为其添加加权平均值(使用用户提供的权重),然后在每个系列(列)上执行蒙特卡罗模拟(这导致从原始数据中采样的1000个随机序列)用户数据和增加的加权平均值。其结果保存为一个巨大的嵌套列表。之后,它会根据生成的蒙特卡罗系列计算一些统计数据,并根据这些统计数据绘制图表和表格。该应用程序还允许在运行后更改权重,然后仅重新运行加权平均部分。
采样是通过lapply完成的,但是使用parLapply完成统计数据的计算。 parLapply中使用的集群存储在全局变量中,并在整个应用程序中重用。
问题是,当用户首次运行应用程序时,提供的文件中的每个列大约需要5秒才能进行处理(假设有1000次模拟)。然而,在第二次运行时(用新权重重新运行加权平均值),单独加权平均需要大约30秒。 我使用Rprof来尝试了解额外时间的来源,我发现第二次运行时序列化函数需要大约20秒,而我在第一次运行时需要大约半秒钟(这是用户提供的数据中的每列)
我尝试了不同的方法来解决这个问题。 起初我认为这可能是因为第二次运行的数据有些不同(不同的结构,无论如何)但是当我用固定的种子进行采样并将结果与第二次运行的数据进行比较时它们是相同的(idendical()) 接下来,我尝试将在全局对象中保存数据的变量设置为NULL,然后再为其分配新值,这对我们没有帮助。 我甚至尝试在重新运行之前在集群内部使用垃圾收集器。没有帮助。
以下是我得到的两个Rprof结果
第一次跑的最后一系列
$by.self
self.time self.pct total.time total.pct
"unserialize" 3.38 79.72 3.38 79.72
"serialize" 0.50 11.79 0.50 11.79
"is.matrix" 0.16 3.77 0.16 3.77
"is.factor" 0.04 0.94 0.04 0.94
"<Anonymous>" 0.02 0.47 4.24 100.00
"rbind" 0.02 0.47 0.36 8.49
"%in%" 0.02 0.47 0.06 1.42
"match" 0.02 0.47 0.04 0.94
"attr" 0.02 0.47 0.02 0.47
"names" 0.02 0.47 0.02 0.47
"nargs" 0.02 0.47 0.02 0.47
"seq.int" 0.02 0.47 0.02 0.47
$by.total
total.time total.pct self.time self.pct
"<Anonymous>" 4.24 100.00 0.02 0.47
".Call" 4.24 100.00 0.00 0.00
".func" 4.24 100.00 0.00 0.00
"do.call" 4.24 100.00 0.00 0.00
"doTryCatch" 4.24 100.00 0.00 0.00
"eval" 4.24 100.00 0.00 0.00
"evalq" 4.24 100.00 0.00 0.00
"flushReact" 4.24 100.00 0.00 0.00
"FUN" 4.24 100.00 0.00 0.00
"func" 4.24 100.00 0.00 0.00
"handler" 4.24 100.00 0.00 0.00
"isolate" 4.24 100.00 0.00 0.00
"lapply" 4.24 100.00 0.00 0.00
"MCres" 4.24 100.00 0.00 0.00
"Monte.Carlo" 4.24 100.00 0.00 0.00
"parSummary" 4.24 100.00 0.00 0.00
"run" 4.24 100.00 0.00 0.00
"runApp" 4.24 100.00 0.00 0.00
"service" 4.24 100.00 0.00 0.00
"serviceApp" 4.24 100.00 0.00 0.00
"shinyCallingHandlers" 4.24 100.00 0.00 0.00
"try" 4.24 100.00 0.00 0.00
"tryCatch" 4.24 100.00 0.00 0.00
"tryCatchList" 4.24 100.00 0.00 0.00
"tryCatchOne" 4.24 100.00 0.00 0.00
"withCallingHandlers" 4.24 100.00 0.00 0.00
"withVisible" 4.24 100.00 0.00 0.00
"clusterApply" 3.88 91.51 0.00 0.00
"parLapply" 3.88 91.51 0.00 0.00
"staticClusterApply" 3.88 91.51 0.00 0.00
"unserialize" 3.38 79.72 3.38 79.72
"recvData" 3.38 79.72 0.00 0.00
"recvData.SOCKnode" 3.38 79.72 0.00 0.00
"serialize" 0.50 11.79 0.50 11.79
"postNode" 0.50 11.79 0.00 0.00
"sendCall" 0.50 11.79 0.00 0.00
"sendData" 0.50 11.79 0.00 0.00
"sendData.SOCKnode" 0.50 11.79 0.00 0.00
"rbind" 0.36 8.49 0.02 0.47
"[[" 0.26 6.13 0.00 0.00
"[[.data.frame" 0.26 6.13 0.00 0.00
"is.matrix" 0.16 3.77 0.16 3.77
"%in%" 0.06 1.42 0.02 0.47
"is.factor" 0.04 0.94 0.04 0.94
"match" 0.04 0.94 0.02 0.47
"attr" 0.02 0.47 0.02 0.47
"names" 0.02 0.47 0.02 0.47
"nargs" 0.02 0.47 0.02 0.47
"seq.int" 0.02 0.47 0.02 0.47
$sample.interval
[1] 0.02
$sampling.time
[1] 4.24
第二次运行(一系列,加权平均值)
$by.self
self.time self.pct total.time total.pct
"serialize" 27.82 88.32 27.82 88.32
"unserialize" 3.46 10.98 3.46 10.98
"rbind" 0.06 0.19 0.22 0.70
"match" 0.06 0.19 0.06 0.19
"<Anonymous>" 0.02 0.06 31.50 100.00
"[[" 0.02 0.06 0.14 0.44
"[[.data.frame" 0.02 0.06 0.12 0.38
"%in%" 0.02 0.06 0.08 0.25
"is.factor" 0.02 0.06 0.02 0.06
$by.total
total.time total.pct self.time self.pct
"<Anonymous>" 31.50 100.00 0.02 0.06
".Call" 31.50 100.00 0.00 0.00
".func" 31.50 100.00 0.00 0.00
"do.call" 31.50 100.00 0.00 0.00
"doTryCatch" 31.50 100.00 0.00 0.00
"eval" 31.50 100.00 0.00 0.00
"evalq" 31.50 100.00 0.00 0.00
"flushReact" 31.50 100.00 0.00 0.00
"FUN" 31.50 100.00 0.00 0.00
"func" 31.50 100.00 0.00 0.00
"handler" 31.50 100.00 0.00 0.00
"isolate" 31.50 100.00 0.00 0.00
"lapply" 31.50 100.00 0.00 0.00
"MCres" 31.50 100.00 0.00 0.00
"Monte.Carlo" 31.50 100.00 0.00 0.00
"parSummary" 31.50 100.00 0.00 0.00
"run" 31.50 100.00 0.00 0.00
"runApp" 31.50 100.00 0.00 0.00
"service" 31.50 100.00 0.00 0.00
"serviceApp" 31.50 100.00 0.00 0.00
"shinyCallingHandlers" 31.50 100.00 0.00 0.00
"try" 31.50 100.00 0.00 0.00
"tryCatch" 31.50 100.00 0.00 0.00
"tryCatchList" 31.50 100.00 0.00 0.00
"tryCatchOne" 31.50 100.00 0.00 0.00
"withCallingHandlers" 31.50 100.00 0.00 0.00
"withVisible" 31.50 100.00 0.00 0.00
"clusterApply" 31.28 99.30 0.00 0.00
"parLapply" 31.28 99.30 0.00 0.00
"staticClusterApply" 31.28 99.30 0.00 0.00
"serialize" 27.82 88.32 27.82 88.32
"postNode" 27.82 88.32 0.00 0.00
"sendCall" 27.82 88.32 0.00 0.00
"sendData" 27.82 88.32 0.00 0.00
"sendData.SOCKnode" 27.82 88.32 0.00 0.00
"unserialize" 3.46 10.98 3.46 10.98
"recvData" 3.46 10.98 0.00 0.00
"recvData.SOCKnode" 3.46 10.98 0.00 0.00
"rbind" 0.22 0.70 0.06 0.19
"[[" 0.14 0.44 0.02 0.06
"[[.data.frame" 0.12 0.38 0.02 0.06
"%in%" 0.08 0.25 0.02 0.06
"match" 0.06 0.19 0.06 0.19
"is.factor" 0.02 0.06 0.02 0.06
$sample.interval
[1] 0.02
$sampling.time
[1] 31.5
有谁知道可能导致这种情况的原因? 提前谢谢!
编辑(2014年7月14日):
我和任务经理一样检查了史蒂夫的建议。
第一次运行似乎很正常: master使用CPU - &gt;工人使用CPU - &gt; master使用CPU - &gt;工人使用CPU - &gt; ... 我想这是因为大师交出工作,工人处理并重复。似乎很正常。
在第二轮(奇怪的慢速)上,它看起来有点不同: master几乎一直使用CPU,但不是全部(在我的任务管理器中最多13%,从5-8%继续使用master),而工作CPU使用率是开关的。我使用3名工人,而在第一次运行时,他们在处理时都使用了13%,然后在不工作(0%)到满容量(13%)之间波动,同时主人不断使用5-8%的CPU
我还在parLapply调用之前设置了一个浏览器,并在我的数据上手动运行serialize函数(以NULL作为连接)然后它几乎是即时的(在一秒钟之内)。
另外,我尝试了useXDR = FALSE开关,但是当我打开时,我的程序甚至没有完成第一次运行(设置为FALSE)。在第一次运行的第三次迭代中,它只是停止处理并无限期地挂起(master和worker占用了0%的CPU)。
我在我的代码中添加了一个if块,在第一个之后在其他运行中使用lapply而不是parLapply,因为我现在完全没有想法。这只是一种解决方法,我仍然希望找到问题的根源
再次,非常感谢您的回复!
答案 0 :(得分:1)
不幸的是,仅使用来自主服务器的配置文件数据很难确定问题,并且很难从工作人员那里获取配置文件数据。但是,这些数据确实提供了一些线索。
主服务器使用“serialize”函数通过套接字连接向工作人员发送任务请求,“unserialize”函数用于从工作人员检索任务结果。主人在“反序列化”中花费大量时间是正常和健康的,因为它通常在等待计算任务时必须阻塞(除非你得到了微小任务的不健康状况)。但是“序列化”不应该阻塞,因为主服务器永远不会向工作人员发送任务,除非它认为工作人员已准备就绪并等待任务分配。
因此,工作人员可能表现不佳,因为他们没有足够的内存或遇到网络问题,或者发送给工作人员的任务数据特别难以序列化。我会使用流程监控工具来尝试确定哪一个可能是问题。例如,如果主进程没有占用大量CPU时间,则问题可能出在工作者身上。如果它使用了大量的CPU时间,那么实际的数据序列化可能就是问题。
话虽这么说,您可能希望在创建群集对象时设置useXDR=FALSE
:
library(parallel)
cl <- makePSOCKcluster(detectCores(), useXDR=FALSE)
这可能会显着提高“序列化”和“反序列化”的性能。虽然“useXDR”默认为TRUE
,但我认为仅在一个群集中同时使用小端和大端计算机时才需要XDR,这种情况并不常见。