Ist der Versand der S4-Methode langsam?
Meine S4-Klasse hat eine Methode, die oft aufgerufen wird. Mir ist aufgefallen, dass die Ausführungszeit viel langsamer ist als wenn eine ähnliche Funktion unabhängig aufgerufen würde. Also habe ich meiner Klasse einen Slot mit dem Typ "function" hinzugefügt und diese Funktion anstelle der Methode verwendet. Das folgende Beispiel zeigt zwei Möglichkeiten, und beide sind viel schneller als die entsprechende Methode. Das Beispiel legt außerdem nahe, dass die niedrigere Geschwindigkeit der Methode nicht darauf zurückzuführen ist, dass die Methode Daten aus der Klasse abrufen muss, da die Funktionen auch dann schneller sind, wenn sie dies ebenfalls tun.
Natürlich ist diese Vorgehensweise nicht ideal. Ich frage mich, ob es eine Möglichkeit gibt, den Versand von Methoden zu beschleunigen. Irgendwelche Vorschläge?
setClass(Class = "SpeedTest",
representation = representation(
x = "numeric",
foo1 = "function",
foo2 = "function"
)
)
speedTest <- function(n) {
new("SpeedTest",
x = rnorm(n),
foo1 = function(z) sqrt(abs(z)),
foo2 = function() {}
)
}
setGeneric(
name = "method.foo",
def = function(object) {standardGeneric("method.foo")}
)
setMethod(
f = "method.foo",
signature = "SpeedTest",
definition = function(object) {
sqrt(abs(object@x))
}
)
setGeneric(
name = "create.foo2",
def = function(object) {standardGeneric("create.foo2")}
)
setMethod(
f = "create.foo2",
signature = "SpeedTest",
definition = function(object) {
z <- object@x
object@foo2 <- function() sqrt(abs(z))
object
}
)
> st <- speedTest(1000)
> st <- create.foo2(st)
>
> iters <- 100000
>
> system.time(for (i in seq(iters)) method.foo(st)) # slowest by far
user system elapsed
3.26 0.00 3.27
> # much faster
> system.time({foo1 <- st@foo1; x <- st@x; for (i in seq(iters)) foo1(x)})
user system elapsed
1.47 0.00 1.46
> # retrieving st@x instead of x does not affect speed
> system.time({foo1 <- st@foo1; for (i in seq(iters)) foo1(st@x)})
user system elapsed
1.47 0.00 1.49
> # same speed as foo1 although no explicit argument
> system.time({foo2 <- st@foo2; for (i in seq(iters)) foo2()})
user system elapsed
1.44 0.00 1.45
# Cannot increase speed by using a lambda to "eliminate" the argument of method.foo
> system.time({foo <- function() method.foo(st); for (i in seq(iters)) foo()})
user system elapsed
3.28 0.00 3.29