2014-09-03 77 views
1

方法我一直在尋找實現一些代碼,我原來寫在R導入下的性能改進。到目前爲止,事情一直在順風順水,但我正在努力的一件事是如何在C中實現S3 Generic/Methods,同時最小化開銷。實施S3通用/用C

的應用案例我的函數將大部分時間直接去,我想我可以在通用的實施,或最壞的情況下必須用C默認S3派遣一個級別的默認方法。也就是說,我想允許發生非平凡調度的可能性。

我已經發現了一些引用DispatchOrEval,但似乎這個功能被保留供內部使用,由於在未來的函數定義的src/eval.cattribute_hidden聲明:

attribute_hidden 
int DispatchOrEval(SEXP call, SEXP op, const char *generic, SEXP args, 
      SEXP rho, SEXP *ans, int dropmissing, int argsevald) 
{ 

是否有任何其他的方式來以有限的開銷直接從C實現S3派遣?

僅供參考,我一直在閱讀以下內容:

我承認很多它仍然是相當新的給我,所以我的理解,到目前爲止可能是完全錯誤的。


編輯:解決一個具體的例子馬丁的要求,我想寫像這樣使用時的功能checkArgs(或類似):

FUN <- function(x, y, z) { 
    checkArgs(x=...,y=..., z=...) 
    # More code here 
} 

將提供一個簡單的方法快速檢查參數是我想要的。

例如,像:

FUN <- function(x, y, z) { 
    checkArgs(x=matrix(numeric(), ncol=3),y=..., z=...) 
    # More code here 
} 

將檢查這樣的說法x是一個三列數字矩陣。我想允許發送的功能是將xcheckArgs中的模板規範進行比較的功能(此處未顯示,但可能會將其稱爲alike以比較對象的相似性)。大多數情況下,它會使用默認的C版本,但是如果用戶爲該泛型創建方法並使用該方法的類的對象進行驗證,則將使用提供的方法。

爲了這通常有用的,包括在SPLIT申請,聯合收割機使用的分析,必須checkArgs很快運行。因此,我開始重新編寫C中的比較函數,但這樣做後,失去了我希望保留的調度功能,即使最常見的用例是依賴於默認方法。

+2

你爲什麼要試圖做到這一點?你確定你的瓶頸是S3派遣嗎? – 2014-09-03 02:15:44

+2

我不知道有什麼辦法可以在不調用R函數的情況下執行S3調度。正如Josh所說,你確定S3會放慢你的速度嗎? S3派遣的成本大約爲1-2微秒。最後,最近有一些R源的提交加快了S3的發佈速度,它們將會在下一個版本中出現。 – wch 2014-09-03 02:30:49

+0

@JoshuaUlrich,是的,我確定。我的函數目前在C中的估計時間爲1.5微秒(包括從R開始的初始調用),並且每個S3調度會添加2微秒,其中可能會有幾個微秒。功能旨在被作爲優化儘可能使得它可以令人信服地添加到被運行數百萬次作爲部分R的功能拆分應用 - 結合而不過度損害總執行時間分析類型。 – BrodieG 2014-09-03 11:58:54

回答

1

這絕對不是完全令人滿意,但解決我的問題的一部分。基本上,我們註冊一個虛假的通用那份急件其實之前檢查對象性:

genericfun <- function(x) { 
    if(is.object(x)) { 
    UseMethod("genericfun") 
    } else { 
    #.Call(CFunNativeSymbol, x) 
    } 
} 
genericfun.default <- function(x) { 
    #.Call(CFunNativeSymbol, x) 
} 
obj <- structure(1:100, class="obj") 
non.obj <- 1:100 
microbenchmark(
    genericfun(non.obj), 
    genericfun(obj), 
    genericfun.default(non.obj) 
) 

主要生產(注意,這顯然是我的Windows系統上使勁的microbenchmark精度):

Unit: nanoseconds 
         expr min lq median uq max neval 
     genericfun(non.obj) 367 732 733.0 1098 16457 100 
      genericfun(obj) 6217 6583 6583.0 6949 35838 100 
genericfun.default(non.obj) 0 1 183.5 366 1463 100 

通用調度現在降到微秒以下。

此外,就遞歸使用而言,只有在C中的is.object的求值返回TRUE時才需要調用R通用,因此只包含非對象的遞歸結構無需在任何點從C退出。

有可能使用這種方法(並非最不重要的是它的可怕,黑客性質),這將成爲使用明顯,但這是我能想出現在最好的許多問題。現在想到的一個問題是,隱式類的調度不會發生(例如is.object(matrix()) == FALSE)。