更改时复制
看起来就像R变量不共享任何内存
X <- y <- 1:5 X
## [1] 1 2 3 4 5
y
## [1] 1 2 3 4 5
x[1] <- 2L x
## [1] 2 2 3 4 5
y
## [1] 1 2 3 4 5
x <- 1:5 fun = function(z) {z[1] = 2L;Z} fun(x)
## [1] 2 2 3 4 5
x
## [1] 1 2 3 4 5
R使用“命名”概念,而不是严格的“引用计数”
在行动
x = 1:5 .内部(inspect(x))
## @480c138 13 INTSXP g0c3 [NAM(2)] (len=5, tl=0) 1,2,3,4,5
@41de7d8
:内存地址。13 INTSXP
: integer ' S-expression '(稍后详细介绍)。(南(1))
:一个符号(x
)引用内存中的位置。x = y = 1:5 .内部(inspect(x))
## @48f2f18 13 INTSXP g0c3 [MARK,NAM(2)] (len=5, tl=0) 1,2,3,4,5
(检查(y))
## @48f2f18 13 INTSXP g0c3 [MARK,NAM(2)] (len=5, tl=0) 1,2,3,4,5
x
,y
指向内存中的相同位置(南(2))
:(至少)两个符号引用位置' copy -on-change ':当更新一个向量时,如果Nam () == 2
.
##复制更改x = y = 1:5 .Internal(inspect(x))
## @3f94c98 13 INTSXP g0c3 [NAM(2)] (len=5, tl=0) 1,2,3,4,5
x[1] = 2L .Internal(inspect(x))
## @3cf5db0 13 INTSXP g0c3 [NAM(1)] (len=5, tl=0) 2,2,3,4,5
(检查(y))
## @3f94c98 13 INTSXP g0c3 [NAM(2)] (len=5, tl=0) 1,2,3,4,5
x = 1:5 .内部(inspect(x))
## @3bf3838 13 INTSXP g0c3 [NAM(2)] (len=5, tl=0) 1,2,3,4,5
x[1] = 2L .Internal(inspect(x))
## @3aef798 13 INTSXP g0c3 [NAM(1)] (len=5, tl=0) 2,2,3,4,5
垃圾收集(大致描述)
饱和度指数
),由系统分配到一个可用的s表达式池X <- 1
将SEXP从已分配到“正在使用”池,级别0 (0 ing0c4
的(检查(x))
)rm (x)
,一个符号不再引用SEXP,它是一个可重用的候选符号。gc ()
(手动,或更典型的自动触发时R可用池中SEXP已用完)
注意:SEXP属于“代”和类
Y = 1 fun = function() {x <- 1;2} fun();Gc() #扫描x, y;收集x,保存y
## [1] 2
## used (Mb) gc触发器(Mb) max used (Mb) ## Ncells 503648 26.9 940480 50.3 940480 50.3 ## Vcells 939506 7.2 1941543 14.9 1199408 9.2
有趣的();Gc() #扫描并收集x,不访问y
## [1] 2
## used (Mb) gc触发器(Mb) max used (Mb) ## Ncells 503747 27.0 940480 50.3 940480 50.3 ## Vcells 939776 7.2 1941543 14.9 1199408 9.2
性能的影响
一些常用的使用模式涉及大量的复制!
c ()
,rbind ()
,cbind ()
循环往复data.frame ()
,列表()
或S4对象。使用internal(检查())
跟踪分配到的内存x
在下面的循环中。
X <- integer() n <- 5 for (i in 1:n) X <- c(X, i)
答:
N = 5 x = integer();.Internal(inspect(x)) for (i in 1:n) {x <- c(x, i) .Internal(inspect(x))} x = integer();.Internal(inspect(x)) for (i in 1:n) {x[i] = i .Internal(inspect(x))} x
如果一个整数占用大约8个字节的内存,并且循环中的每次迭代都将当前分配复制到新分配中,那么循环中复制了多少字节n
迭代?
解释的输出tracemem ()
类中的值更新时的内存分配data.frame ()
.有多少data.frame
被复制了吗?
df <- mtcars tracemem(df) #整体data.frame
## [1] "<0x45779e0>"
tracemem(df[[1]]) #指定列
## [1] "<0x1766760>"
df [1]
## [1]
Df [1,1] = 22.1
## tracemem[0x45779e0 -> 0x44fcd68]: eval eval withVisible withCallingHandlers handle timing_fn evaluate_call evaluate in_dir block_exec call_block process_group。block process_group withCallingHandlers process_file <匿名> <匿名> vweave_rmarkdown <匿名> <匿名> do。调用匿名> <# #tracemem[0x44fcd68 -> 0x447ce60]: [<-.data.frame [<- eval eval withVisible withCallingHandlers handle timing_fn evaluate_call evaluate in_dir block_exec call_block process_group.block process_group withCallingHandlers process_file vweave_rmarkdown do.call ## tracemem[0x447ce60 -> 0x447d058]: [<-.data.frame [<- eval eval withVisible withCallingHandlers handle timing_fn evaluate_call evaluate in_dir block_exec call_block process_group.block process_group withCallingHandlers process_file vweave_rmarkdown do.call ## tracemem[0x1766760 -> 0x264a210]: [<-.data.frame [<- eval eval withVisible withCallingHandlers handle timing_fn evaluate_call evaluate in_dir block_exec call_block process_group.block process_group withCallingHandlers process_file vweave_rmarkdown do.call
Df [2,2] = 22.2
## tracemem[0x447d058 -> 0x4464e78]: eval eval withVisible withCallingHandlers handle timing_fn evaluate_call evaluate in_dir block_exec call_block process_group。block process_group withCallingHandlers process_file <匿名> <匿名> vweave_rmarkdown <匿名> <匿名> do。调用匿名> <# #tracemem[0x4464e78 -> 0x4464f20]: [<-.data.frame [<- eval eval withVisible withCallingHandlers handle timing_fn evaluate_call evaluate in_dir block_exec call_block process_group.block process_group withCallingHandlers process_file vweave_rmarkdown do.call ## tracemem[0x4464f20 -> 0x4465070]: [<-.data.frame [<- eval eval withVisible withCallingHandlers handle timing_fn evaluate_call evaluate in_dir block_exec call_block process_group.block process_group withCallingHandlers process_file vweave_rmarkdown do.call
将此与修改类似大小的矩阵时的内存分配进行比较
m <- m1 <- matrix(0, nrow(mtcars), ncol(mtcars)) tracemem(m) #矩阵是一个具有dms属性的向量
## [1] "<0x477afd0>"
M [1,1] = 22.1
## tracemem[0x477afd0 -> 0x45b3820]: eval eval withVisible withCallingHandlers handle timing_fn evaluate_call evaluate in_dir block_exec call_block process_group。block process_group withCallingHandlers process_file <匿名> <匿名> vweave_rmarkdown <匿名> <匿名> do。调用匿名> <
M [2,1] = 22.2
以及“向量化”更新
Df <- mtcars tracemem(Df);tracemem (df [[1]])
## [1] "<0x45779e0>"
## [1] "<0x1766760>"
Df [1:2, 1] <- c(22.1, 22.2)
## tracemem[0x45779e0 -> 0x3f57e58]: eval eval withVisible withCallingHandlers handle timing_fn evaluate_call evaluate in_dir block_exec call_block process_group。block process_group withCallingHandlers process_file <匿名> <匿名> vweave_rmarkdown <匿名> <匿名> do。调用匿名> <# #tracemem[0x3f57e58 -> 0x3f57f00]: [<-.data.frame [<- eval eval withVisible withCallingHandlers handle timing_fn evaluate_call evaluate in_dir block_exec call_block process_group.block process_group withCallingHandlers process_file vweave_rmarkdown do.call ## tracemem[0x3f57f00 -> 0x3f58050]: [<-.data.frame [<- eval eval withVisible withCallingHandlers handle timing_fn evaluate_call evaluate in_dir block_exec call_block process_group.block process_group withCallingHandlers process_file vweave_rmarkdown do.call ## tracemem[0x1766760 -> 0x3d04bd0]: [<-.data.frame [<- eval eval withVisible withCallingHandlers handle timing_fn evaluate_call evaluate in_dir block_exec call_block process_group.block process_group withCallingHandlers process_file vweave_rmarkdown do.call
m <- m1 <- matrix(0, nrow(mtcars), ncol(mtcars)) tracemem(m) #矩阵是一个具有dms属性的向量
## [1] "<0x4615310>"
M [1:2, 1] <- c(22.1, 22.2)
## tracemem[0x4615310 -> 0x3cd6510]: eval eval withVisible withCallingHandlers handle timing_fn evaluate_call evaluate in_dir block_exec call_block process_group。block process_group withCallingHandlers process_file <匿名> <匿名> vweave_rmarkdown <匿名> <匿名> do。调用匿名> <
这是一个简单的函数,实现得很糟糕
F <- function(n) {x <- integer() for (i in 1:n) x <- c(x, i) x}
正确的
相同的()
-非常严格all.equal ()
-允许数值逼近单元测试!
库(testthat) test_that("f()是正确的",{expect_same (f(5), 1:5)})
健壮的
边缘情况,例如长度为0的迭代,NA
在这里,我们添加了一些额外的测试,并将它们放在一个函数中,以便于重用。
测试<-函数(f) {test_that("f()是正确的和健壮的",{expect_alike (f(5), 1:5) expect_alike (f(1), 1L) expect_alike (f(0), integer(0))})}
我们的代码没有通过单元测试,因为1: n
失败与N == 0
tryCatch(tests(f), error = conditionMessage)
##[1]“测试失败:'f()是正确的和健壮的'\n* f(0)不等于整数(0)。\n长度不同:2 vs 0\n"
修改后的代码,对常见用例具有健壮性
F1 =函数(n) {x <- integer() for (i in seq_len(n)) x = c(x, i) x}测试(F1)
快
system.time ()
,但可能会有相当大的运行变化库(微基准)res <-微基准(f1(100), f1(200), f1(400), f1(800), f1(1600)) plot(res)
因为复制,比例是二次方的。解决方案?
F2 <- function(n) {sapply(seq_len(n), function(i) i)} tests(F2) #失败!N == 0
F2a <-函数(n) {if (n == 0) {integer()} else {sapply(seq_len(n),函数(i) i)}}测试(F2a)
f3 <-函数(n) {vapply(seq_len(n),函数(i) i,整数(1))}test_that("f()是正确的",{expect_same (f3(5), 1:5) expect_same (f3(1), 1L) expect_same (f3(0),整数(0))})测试(f3)
F4 <-函数(n) {x <-整数(n) for (i in seq_len(n)) x[[i]] = i x}测试(F4)
F5 <- seq_len tests(F5)
n < - 1000微基准测试(f1 (n), f2a (n), f3 (n), f4 (n), f5 (n))
环境
当前环境
环境()
##
令人惊讶的是R
Env <- new.env() Env [["foo"]] <- 123 Env [["foo"]]
## [1] 123
Get ("foo", env) #等价(不是真的!)
## [1] 123
ls (env)
##[1]“foo”
的名字
或象征
在R是常量时间的查找
“引用”语义(几乎所有其他在R是' copy-on-change '语义)
另一个< - env env[[“酒吧”]]< - 456另一个[[“酒吧”]]
## [1] 456
所有环境都有一个“父”环境
parent.env (env)
##
emptyenv ()
new.env ()
)环境可以作为链表链接在一起
顶部<-新。Env (parent = emptyenv()) mid <- new。Env (parent = top) bot <- new。环境(父=中)
符号(键)查找
前[[“顶级”]]< - 1年中[["中期"]]< - 2机器人[[“bot”]]< - 3所示
在参考环境中没有找到的符号将在父环境中查找
(“机器人”,机器人)
## [1]
(“中期”,机器人)
## [1] 2
tryCatch({get("mid", bot, inherit =FALSE) #限制搜索当前环境},错误=条件消息)
##[1] "对象'mid' not found"
bot[["mid"]]] # NULL;'[['限制当前环境
# #空
赋值给当前环境
Bot [["mid"]] <- 5 Bot [["mid"]]
## [1]
中期[["中期"]]
## [1] 2
功能与环境密切相关
Fun <- function() {environment()} Fun() #环境定义函数体
##
Fun() #新函数,新环境
##
函数中的环境会发生什么变化?
如果一个函数体有一个环境,就必须有一个父环境
Fun <- function() {env <- environment() list(env, parent.env(env))} Fun ()
([1]) # # # # < x4bb9690环境:0 > ## ## [[ 2]] # # <环境:R_GlobalEnv >
Fun <- function() {fun1 <- function() {env1 <- environment() #由fun1创建的环境par1 <- parent.env(env1) #父环境列表(env1 = env1, par1 = par1)} env <- environment() #由Fun par创建的环境<- parent.env(env)列表(env = env, par = par, fun1=fun1)} Fun ()
## $env ## ## ## $par ## ## ## $fun1 ## function () ## {# env1 <- environment() ## par1 <- parent.env(env1) ## list(env1 = env1, par1 = par1) ##} ##
函数的环境的父类就是环境它在其中被定义(与它的命名环境不同)
查找、赋值(<-
)和赋值到父环境(<<-
)
Fun = function() {x0 <- 0 x1 <- 0 fun1 <- function() {y <- 1 #创建局部变量y x1 <<- 2 #赋给父环境(s)中第一个出现'x'的地方z <<- 3 #父环境(s)中没有z,因此在top环境中创建c(x0 = x0, x1 = x1, y = y, z = z)} result <- fun1() list(x0 = x0, x1 = x1, result = result)}
这叫做词法作用域
包名称空间、导入和search ()
search()路径
search ()
##[1]”。GlobalEnv“包:微基准”##[3]“包:测试”“包:BiocStyle”##[5]“包:stats”“包:图形”##[7]“包:grDevices”“包:utils”##[9]“包:数据集”“包:方法”##[11]“自动加载”“包:基础”
库(BiocGenerics)
:装载和装载包裹
包命名空间为加载进入水流R会话
包含从包中导出的符号的环境为附加到R搜索路径
“附加”一个包意味着.GlobalEnv
的父文件指向新包导出的符号环境。新包导出的符号环境指向先前由所指向的包.GlobalEnv
包由NAMESPACE组成
.GlobalEnv
.包中的符号解析遵循词法范围
.GlobalEnv
,那么……评价,懒惰和不规范的评价
练习:银行账户
恭喜你,你拥有一家银行!下面是一个函数,它创建一个帐户,并提供对该帐户的访问
账户<-函数(){余额<- 0可用<-函数(){}存款<-函数(amt){}提取<-函数(amt){}列表(可用=可用,存款=存款,提取=提取)}
答:
账户<-函数(){余额<- 0可用<-函数(){余额}存款<-函数(amt){余额<<-余额+ amt余额}提现<-函数(amt){如果(amt >余额)停止(“资金不足”)存款(-amt)}列表(可用=可用,存款=存款,提现=提现)}
实现以下测试用例,使用词汇作用域的概念:
library(testthat) test_that("I understand lexical scope", {acct1 <- account() expect_equal(acct1$deposit(10), 10) expect_equal(acct1$deposit(12), 22) expect_equal(acct1$available(), 22) expect_equal(acct1$withdraw(20), 2) expect_error(acct1$withdraw(20), "资金不足")})
如果你有了第二个客户会怎么样?
Test_that("函数创建本地作用域",{acct1 <- account();Acct1 $deposit(10) acct2 <- account();Acct2 $deposit(20) expect_equal(acct1$available(), 10) expect_equal(Acct2 $available(), 20)})
答:
账户<-函数(){余额<- 0可用<-函数(){余额}存款<-函数(amt){余额<<-余额+ amt乐趣}提取<-函数(amt){如果(amt >余额)停止(“资金不足”)存款(-amt)}乐趣=列表(可用=可用,存款=存款,提取=提取)乐趣}
练习:银行账户2
需要对实现进行哪些更改才能允许
Test_that ("endomorphisms rock", {expect_equal(account()$deposit(10)$withdraw(5)$available(), 5)})
练习:package-local选项
实现用户可以通过函数设置的“package-local”选项。通过使用本地()
创建并填充包含包局部变量和访问器函数的环境get ()
而且设置()
检索/赋值变量,例如:宽容
.这里是一个开始,还有一些单元测试
.myoptions <- local({公差= 1e-4 get = function(){公差}set = function(value){} ##…}) ##环境耐受=…
答:
.myoptions <- local({公差= 1e-4 get = function()公差列表(get = get, set = function(value) {ovalue <- get()公差<- value ovalue})}) getTolerance <- .myoptions$get settolance <- .myoptions$set
这里有一些单元测试
test_that("本地选项可以设置",{expect_equal(getTolerance(), 1e-4) ## setTolerance()返回之前的值,以方便重置expect_equal(otol <- setTolerance(1e-5), 1e-4) expect_equal(setTolerance(otol), 1e-5)})
F <- function(x){##…G ()} G <- function(x){##…if (log(x) < 0) {TRUE} else {FALSE}}
调用回溯()
后的错误。
f(1)回溯()
debugonce (g)
:当函数被调用时,进入' browser '。看到浏览器吗?
为了能做的事。变体:调试(g)
...undebug (g)
.
debugonce(g) f(-1) ##浏览器[2]> ##…
浏览器()
.编辑源代码(对于复杂或包代码不太实用)
G <- function(x){##…browser() if (log(x) < 0) {TRUE} else {FALSE}}
选项(错误=恢复)
.当完成时,选项(错误= NULL)
.实际上,任何函数接受0参数是可能的recover,例如:选项(错误=回溯)
.
f(-1) ##错误:所有(x >= 0)不是TRUE ## ##输入帧号,或0退出## ## 1:f(-1) ## 2: stopifnot(x >= 0)) ## ##选择:2 ##调用从:f(-1) ##浏览[1]> c ## ##输入帧号,或0退出## ## 1:f(-1) ## 2: #2: stopifnot(所有(x >= 0)) ## ##选择:
trace ()
-对跟踪执行特别有用(例如,Tracer = quote(print(argname))
),对于S4方法(参数签名=
)
## like debug trace(g, trace =browser) f(-1)
Trace (g, quote({print(x);Print (log(x))})) for (i in runif(1000, - 1,100)) f(i) trace(g, quote(if (x < 0) browser()) for (i in runif(1000, - 1,100)) f(i)
library(GenomicRanges) showMethods("findOverlaps") selectMethod("findOverlaps", c("GRanges", "GRanges")) trace(findOverlaps, browser, signature=c("GenomicRanges", "GenomicRanges"))
发现了一个漏洞,现在怎么办?
更优雅地恢复。(从某种程度上说,这不是一个好的解决方案——宁愿避免问题,也不愿治疗症状)。
G <- function(x){##…tryCatch({if (log(x) < 0) TRUE else FALSE},错误=函数(e) {NA})
更聪明/健壮地编程-在我们的简单示例中如果()
是无关的,并引入一个神秘的错误消息!
G <- function(x){##…log(x) < 0 # NA,而不是if (NA) (!)
最佳方法:提出前提条件(并更巧妙地编程)。
f (x) < -函数{stopifnot (is.numeric (x) (x) = = 1,长度! is.na (x) x > = 0) # #……g (x)}
结构:具有特定文件和结构的简单目录
创建
devtools::创建(“MyPackage”)
发展
devtools: load_all ()
减少编辑-安装-运行循环。devtools: use_testthat ()
而且devtools::测试()
为testthat单元测试。devtools:文档()
(roxygen2)查阅文件。devtools::测试()
(运行单元测试);devtools::检查()
devtools:安装()
注意:
最后仲裁者:
R CMD建立mypackag#源代码版本为0.99.1的包R CMD检查MyPackage_0.99.1.tar.gz
管理
S-expressions
数字()
,逻辑()
,等等),列表,环境,函数等等,都是用C来表示的结构体
年代结构体
被称为“s表达式”,由符号表示饱和度指数
(我读作' S-exp ')饱和度指数
定义为Rinternals.h饱和度指数
是多态的-结构的解释取决于类型信息包含在饱和度指数
本身。类型被列举为INTSXP
,REALSXP
,……STRSXP
:字符()
,字符向量的每个元素都是aCHARSXP
.VECSXP
:列表()
;LISTSXP
是一个“对列表”,主要用于表示函数参数。EXTPTRSXP
:一个R中未表示的任意数据的引用R例如,c++类。饱和度指数
包含sexpinfo,具有命名、垃圾收集、标记等状态,以及实际数据(例如,一个的整数整型()
向量。饱和度指数
数据结构。几个风格长度()
,Rf_length ()
Rf_ *
风格。从RC
internal ()
,.External ()
,. c ()
,打电话给()
,……. c ()
:R强制是否有效R类型,例如,整型()
来C类型,int *
;适用于许多轻量级用途。字符()
更复杂的物体更难处理。打电话给()
:R参数表示为饱和度指数
饱和度指数
在c++语言中。公共API
什么时候该担心?
. c ()
打电话给()
创建一个包和“src”目录。添加链接:
类提供的(c++)头文件黑洞(' Boost Headers ')包。
devtools::create("/tmp/uuid", list(linkto = "BH"))
##在/tmp目录下创建uuid包
##没有发现描述。用价值创造:
##包:uuid ##标题:包的功能(一行,标题大小写)##版本:0.0.0.9000 ## Authors@R: person("First", "Last", email = "first.last@example.com", role = c("aut", "cre")) ##描述:包的功能(一段)##取决于:R(>= 3.4.0) ##许可:它在什么许可下?##编码:UTF-8 ## LazyData: true ##链接到:BH
## *创建uuid。Rproj` from template.
## *添加' . rproj。用户','。Rhistory`, `.RData` to ./.gitignore
dir.create(“/ tmp / uuid / src”)
编写单元测试
devtools:: use_testthat(“/ tmp / uuid”)
## *添加测试建议
## *创建“tests/testthat”。
## *创建“tests/testthat.”R '来自template。
cat(' context("uuid") test_that("uuid返回不同的值",{expect_true(is.character(uuid())) expect_true(长度(uuid()) == 1L) uu <- unique(unlist(复制(100,uuid()))) expect_same(长度(uu), 100L)})', file = "/tmp/uuid/tests/testthat/test_uuid. txt /uuid . txt /uuid . txt ")R”)
实现c++层
Cat (' #include #include static boost::uuids::random_generator uuid_generator = boost::uuids::random_generator();Std::string uuid_generate(){返回boost::uuids::to_string(uuid_generator());} ', file = "/tmp/uuid/src/uuid.cpp")
实现从c++到的接口R的C层。
cat(' #include SEXP uuid(){返回mkString(uuid_generate().c_str());} ', file = "/tmp/uuid/src/uuid.cpp", append = TRUE)
实现接口C来R.
cat(' #include extern "C" {static const R_CallMethodDef callMethods[] ={{"。uuid", (DL_FUNC) &uuid, 0}, {NULL, NULL, 0}};void R_init_uuid(DllInfo *info) {R_registerRoutines(info, NULL, callMethods, NULL, NULL);}}', file = "/tmp/uuid/src/uuid.cpp", append = TRUE)
中实现最终用户APIR.
cat(" #' @useDynLib uuid, .registration = TRUE #' @export uuid <- function() .Call(.uuid), file = "/tmp/uuid/R/uuid. "R”)
文档,测试,安装,使用!
devtools:文档(“/ tmp / uuid”)
##更新uuid文档
##加载uuid
##重新编译uuid
## '/home/mtmorgan/bin/R-3-4-branch/bin/R'——no-site-file——no-environ \ ##——no-save——no-restore——quiet CMD安装'/tmp/uuid' \ ##——library='/tmp/RtmpPZvmxO/devtools_install_20c366d77c59'——no-R \ ##——no-data——no-help——no-demo——no-inst——no-docs——no-exec \ ##——no-multiarch——no-test-load
# #
##更新/tmp/uuid/DESCRIPTION下的roxygen版本
##写入命名空间
devtools::测试(“/ tmp / uuid”)
##加载uuid
##测试uuid
## uuid:…# # # # ========================================================================
devtools::安装(“/ tmp / uuid”)
##安装uuid
## '/home/mtmorgan/bin/R-3-4-branch/bin/R'——no-site-file——no-environ \ ##——no-save——no-restore——quiet CMD安装'/tmp/uuid' \ ##——library='/home/mtmorgan/R/x86_64-pc-linux-gnu-library/3.4- bios -3.6' \ ##——INSTALL -tests
# #
##重新加载已安装的uuid
添加以下单元测试并实现适当的功能
test_that("uuid返回多个值",{n <- 5 result <- uuid(5) expect_true(is.character(result)) expect_same (length(result), 5L) expect_same (length(unique(result)), 5L)})
从“简单”到“难”,分几个阶段来做
实现R通过添加参数来建立基础设施n
对的定义R层次的uuid ()
.提供n
使用默认值,以便原始单元测试继续工作,即devtools::测试(“/ tmp / uuid”)
还是通过了最初的测试
传递参数n
C.做加法n
到R层次的打电话给()
.然后修改c级uuid ()
接受SEXP作为参数,因此签名为SEXP uuid(SEXP n_sexp)
.更新callMethods []
数组,这样uuid
函数有一个参数。测试源代码编译时使用的方法,例如,devtools::安装(“/ tmp / uuid”)
或者再次运行单元测试。
在C、修改uuid ()
检查实参是否为标量整数。通过使用宏来做到这一点吗IS_SCALAR ()
和功能Rf_asInteger ()
常数R_NaInt
;查看头文件' Rinternals.h 'R.home(包括)
.用Rf_error ()
.您将添加如下代码
bool test = IS_SCALAR(n_sexp, INTSXP) && (R_NaInt != Rf_asInteger(n_sexp));if (!test) Rf_error("'n'不能被强制为整数(1)而不是NA");int n = Rf_asInteger(n_sexp);
修改uuid ()
分配一个SEXP来包含结果-一个长度的STRSXPn
.这个已分配的SEXP需要防止垃圾收集,因为它是一个R内存分配与符号无关。保护是由保护()
宏,它被传统地封装在返回SEXP的函数周围。
SEXP结果=保护(Rf_allocVector(n, STRSXP));
使用C循环填充返回向量,为使用的每个元素构造CHARSXPmkChar ()
和设置我
的第Th元素结果
使用函数SET_STRING_ELT ()
.尽管在R在level中,向量的第一个元素是元素1,在C中,第一个元素是0。
For (int I = 0;I < n;++i) SET_STRING_ELT(result, i, mkChar(uuid_generate().c_str()));
我们的任务完成了;使用解除()
删除已分配的SEXP(在本例中为调用函数)上的保护R它本身负责保护它接收到的任何SEXP),并将结果返回给R.
解除(1);返回结果;
(可选)对我们的用户来说,强迫他们R程度的参数n
到一个整数(例如,它们可以提供5
而不是5 l
作为论证)。这可以在R使用水平as.integer ()
,或在C级使用以下。考虑每种方法的优点。
n_sexp = PROTECT(Rf_coerceVector(n_sexp, INTSXP));
使用。创建新包Rcpp: Rcpp.package.skeleton ()
.编辑要包含的DESCRIPTION文件黑洞
在链接:
字段。
添加文件src / rcpp_uuid.cpp
与助推相关的代码
#include #include static boost::uuids::random_generator uuid_generator = boost::uuids::random_generator();Std::string uuid_generate(){返回boost::uuids::to_string(uuid_generator());}
包括Rcpp.h
头,并使用Rcpp命名空间
#包含使用命名空间Rcpp;
使用Rcpp结构实现函数,如CharacterVector
;不需要担心强迫论点,保护等。装饰功能/ / [[Rcpp:出口]]
属性。
// [[Rcpp::export]] CharacterVector rcpp_uuid(int n) {CharacterVector uuids(n);For (int I = 0;I < uuids.size();++i) uuids[i] = uuid_generate();返回uuid;}
在R,使Rcpp处理属性;看看src / RcppExports.cpp
而且R / RcppExports。R
> Rcpp: compileAttributes ()
安装和使用!
Rcppuuid$ R CMD安装。[…] rcpppuuid $ R——vanilla -e " rcpppuuid::rcpp_uuid(3)"> rcpp_uuid::rcpp_uuid(3) [1] "cb9cc7e8-bfcb-4262-b05b-2f1c0a4bc196" [2] "7b592e1f-8341-4da0-af04-b387726af8ea" [3] "7b2ade09-6ff2-4e76-b564-31b1a626e864"
设置
广东发展银行
在linux上,lldb
在Mac;[gdb-to-lldb][gdb-lldb]命令映射一种方法:
$ cat ~/。R/Makevars CFLAGS = -g -O0 CXXFLAGS = -g -O0 CXX11FLAGS = -g -O0
选择:配置R用适当的CFLAGS
等。
整体
从GitHub获取并安装uuid包的副本
$ git克隆https://github.com/Bioconductor/BiocAdvanced $ cd BiocAdvanced $ git checkout苏黎世-2017 $ cd inst/uuid $ R CMD安装。
开始R并启动调试器
$ R -d gdb
启动R处理、加载包等,进入调试器
(gdb) run > library(uuid) > uuid()错误在uuid():无效的类型/长度(符号/16)在向量分配
进入调试器,将断点设置在R抛出错误,并继续
> ^C (gdb) break Rf_error (gdb) continue >
触发错误
> uuid()断点1,Rf_error (format=0x643020 "invalid type/length (%s/%d) in vector allocation") at /home/mtmorgan/src/ r -3-4-branch/src/main/errors.c:821 821 {(gdb)
发现在哪里
您在调用堆栈中。大部分时间我们都在R的源代码,不太可能有bug(虽然不是不可能!
(gdb) where #0 Rf_error (format=0x643020 "invalid type/length (%s/%d) in vector allocation") at /home/mtmorgan/src -3-4-branch/src/main/errors.c:821 #1 0x0000000000525dbc in Rf_allocVector3 (type=1, length=16, allocator=0x0) at /home/mtmorgan/src -3-4-branch/src/main/memory.c:2612 #2 0x000000000050e5c0 in Rf_allocVector (type=1, length=16, allocator=0x0)长度=16)at /home/mtmorgan/src/ r -3-4-branch/src/include/ rinlinedfun .h:196 #3 0x00007fffed786780 in uuid(n_sexp=0x21a16a8) at uuid.cpp:26 #4 0x000000000048b7e3 in R_doDotCall (ofun=0x7fffed7866ac , nargs=1, cargs=0x7fffffffbdd0, call=0x19f7d48) at /home/mtmorgan/src/ r -3-4-branch/src/main/dotcode.c:570
导航和环顾四周
本课程中报告的研究得到了国家人类基因组研究所和国家卫生研究院国家癌症研究所的支持,资助编号为U41HG004059和U24CA180996。
该项目已获得欧盟地平线2020研究和创新计划(资助协议编号633974)下欧洲研究委员会(ERC)的资助。