R序列化功能在某些情况下会变慢

时间:2014-07-10 11:39:55

标签: r serialization parallel-processing shiny

我有一个闪亮的应用程序,它接受用户提供的数据,为其添加加权平均值(使用用户提供的权重),然后在每个系列(列)上执行蒙特卡罗模拟(这导致从原始数据中采样的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,因为我现在完全没有想法。这只是一种解决方法,我仍然希望找到问题的根源

再次,非常感谢您的回复!

1 个答案:

答案 0 :(得分:1)

不幸的是,仅使用来自主服务器的配置文件数据很难确定问题,并且很难从工作人员那里获取配置文件数据。但是,这些数据确实提供了一些线索。

主服务器使用“serialize”函数通过套接字连接向工作人员发送任务请求,“unserialize”函数用于从工作人员检索任务结果。主人在“反序列化”中花费大量时间是正常和健康的,因为它通常在等待计算任务时必须阻塞(除非你得到了微小任务的不健康状况)。但是“序列化”不应该阻塞,因为主服务器永远不会向工作人员发送任务,除非它认为工作人员已准备就绪并等待任务分配。

因此,工作人员可能表现不佳,因为他们没有足够的内存或遇到网络问题,或者发送给工作人员的任务数据特别难以序列化。我会使用流程监控工具来尝试确定哪一个可能是问题。例如,如果主进程没有占用大量CPU时间,则问题可能出在工作者身上。如果它使用了大量的CPU时间,那么实际的数据序列化可能就是问题。

话虽这么说,您可能希望在创建群集对象时设置useXDR=FALSE

library(parallel)
cl <- makePSOCKcluster(detectCores(), useXDR=FALSE)

这可能会显着提高“序列化”和“反序列化”的性能。虽然“useXDR”默认为TRUE,但我认为仅在一个群集中同时使用小端和大端计算机时才需要XDR,这种情况并不常见。