2016-06-07 2 views
0

Рассмотрят следующие функции foo и bar (отличаются только предупреждением печати) и их R эквиваленты fooR и barR:Почему Rcpp :: warning() работает медленнее, чем предупреждение R?

cppFunction(' 
void foo() { 
    int i = 0; 
    while (i < 1e3) { 
    i++; 
    } 
    return; 
}') 

cppFunction(' 
void bar() { 
    int i = 0; 
    while (i < 1e3) { 
    i++; 
    Rcpp::warning("hello world!"); 
    } 
    return; 
}') 

fooR <- function() { 
    i = 0; 
    while (i < 1e3) { 
    i = i+1; 
    } 
} 

barR <- function() { 
    i = 0; 
    while (i < 1e3) { 
    i = i+1; 
    warning("hello world!") 
    } 
} 

Очевидно, что печать предупреждение делает функцию медленнее, но разница между R и Rcpp огромна (200 в несколько раз медленнее против 5000 раз медленнее!):

> benchmark(foo(), bar()) 
    test replications elapsed relative user.self sys.self user.child sys.child 
2 bar()   100 5.156  5156  5.156  0   0   0 
1 foo()   100 0.001  1  0.000  0   0   0 
There were 50 or more warnings (use warnings() to see the first 50) 

> benchmark(fooR(), barR()) 
    test replications elapsed relative user.self sys.self user.child sys.child 
2 barR()   100 11.102 213.5 11.104  0   0   0 
1 fooR()   100 0.052  1.0  0.052  0   0   0 
There were 50 or more warnings (use warnings() to see the first 50) 

Почему это так? Можно ли это предотвратить?

+0

Очевидно, Rcpp должен сделать больше работы, чтобы отправить предупреждение в поток stderr R. Вы можете посмотреть исходный код, чтобы исследовать это. Однако почему вас это беспокоит? У вас есть прецедент, в котором так много предупреждений? – Roland

+0

@Roland Мне нужно проверить входные значения для исключений и возвращать предупреждения в каждом случае - вот как я заметил, что, похоже, это замедление. – Tim

+3

Сотни предупреждений не очень полезны. Я попытался бы избежать этого и использовать функцию для проверки ввода, которая объединяет эти многочисленные предупреждения в одно или несколько предупреждений или, возможно, даже возвращает ошибку. – Roland

ответ

3

Я не уверен, если вы понимаете, из вашего теста, что Rcpp является:

  1. 11,102/5.156 = 2.15322 раза быстрее в метании предупреждение
  2. 0,052/0,001 = 52 раз быстрее в случае с чистым контуром.

Теперь, когда вы бросаете предупреждение, в какRcpp и base R, следующее происходит: открывается

  1. поток в STDERR. (Следовательно, красный текст вместо STDOUT «s черный)
  2. Написать сообщение
  3. Закрыть STDERR
  4. Продолжить инструкции.

В Rcpp, ссылка на низком уровне помогает снизить общее количество времени, которое требуется, чтобы повторить вышеописанную процедуру и возвращает управление к петле против обработчика R, которая сидит выше в стеке.

Опять же, время, необходимое для завершения работы с Rcpp, является нормальным, поскольку оно должно уступить управление процессу обратно на R, распечатать сообщение, а затем вернуться в цикл. Лучший способ подумать о потере скорости из случая с чистым контуром - вы решили вызвать функцию на основе R в цикле C++ вместо цикла R, ожидающего ускорения.

Честно говоря, я немного удивлен тем, что Rcpp был в 2 раза быстрее, чем эквивалент R.