--- title: "新手指引" author: - name: Jiefei Wang affiliation: Roswell Park Comprehensive Cancer Center, Buffalo, NY date: "`r Sys.Date()`" output: BiocStyle::html_document: toc: true toc_float: true vignette: > %\VignetteIndexEntry{quickStartChinese} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} package: SharedObject --- ```{r setup, include = FALSE} # knitr::knit("vignettes/quick_start_guide.Rmd", output = "README.md") knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) library("SharedObject") SharedObject:::setVerbose(FALSE) ``` # ä»‹ç» åœ¨R的多进程并行è¿ç®—ä¸ï¼Œå¦‚æžœæ¯ä¸ªè¿›ç¨‹éœ€è¦è¯»å–åŒä¸€ä¸ªæ•°æ®ï¼Œå¸¸è§çš„åšæ³•就是将数æ®è¯»å…¥æ¯ä¸ªè¿›ç¨‹å†…,然åŽå†è¿›è¡Œè¿ç®—ã€‚è™½ç„¶è¿™ç§æ–¹æ³•简å•直接,但是对于åªè¯»æ•°æ®æ¥è¯´ï¼Œè¿™æ˜¯ä¸€ç§æžå¤§çš„å†…å˜æµªè´¹ã€‚举个例å,在一个常è§çš„4æ ¸8线程的计算机上é¢ï¼Œå¦‚果进行8个进程的并行è¿ç®—,需è¦è¯»å–的数æ®ä¸º1GB, 那么总共就需è¦8GB的内å˜ç”¨ä»¥åŠ è½½æ•°æ®ã€‚在生物å¦é¢†åŸŸï¼Œè¿™ç§é—®é¢˜ä¼šæ›´åР䏥é‡ï¼Œåƒé«˜é€šé‡æµ‹åºåŠ¨è¾„å‡ ä¸ªGB的大å°ï¼Œå¦‚果希望将数æ®å…¨éƒ¨è¯»å…¥å†…å˜ï¼Œé‚£ä¹ˆéœ€è¦çš„é…置将会éžå¸¸æ˜‚贵。 `SharedObject` 是一个用æ¥è§£å†³å¹¶è¡Œè¿ç®—内å˜é—®é¢˜çš„package, 它å¯ä»¥å°†ä¸€ä¸ªR对象的数æ®å˜æ”¾åœ¨å…±äº«å†…å˜ä¸ï¼Œä½¿å¾—多个进程å¯ä»¥è¯»å–åŒä¸€ä¸ªæ•°æ®ï¼Œå› æ¤åªè¦æ•°æ®å¯ä»¥æ”¾å…¥å†…å˜ï¼Œæ— 论使用多少R进程è¿ç®—都ä¸ä¼šå¢žåР内å˜è´Ÿæ‹…ã€‚è¿™æ ·å¯ä»¥æžå¤§å‡å°‘并行è¿ç®—ä¸å†…å˜çš„瓶颈。 # 基础用法 ## 通过现有的对象创建共享对象 如果希望以现有的Rå¯¹è±¡ä¸ºæ¨¡ç‰ˆåˆ›å»ºå…±äº«å¯¹è±¡ï¼Œä½ åªéœ€è¦è°ƒç”¨`share`函数,并且将Rå¯¹è±¡ä½œä¸ºå‚æ•°ä¼ å…¥å³å¯ã€‚在下é¢çš„例åä¸ï¼Œæˆ‘们将创建一个3*3的矩阵`A1`,然åŽè°ƒç”¨`share`函数创建一个共享对象`A2` ```{r} ## Create data A1 <- matrix(1:9, 3, 3) ## Create a shared object A2 <- share(A1) ``` 对于R使用者æ¥è¯´ï¼Œ`A1`å’Œ`A2`æ˜¯å®Œå…¨ä¸€æ ·çš„ã€‚æ‰€æœ‰å¯ä»¥ç”¨äºŽ`A1`的代ç 都å¯ä»¥æ— ç¼è¡”接到`A2`上é¢ï¼Œæˆ‘们å¯ä»¥æ£€æŸ¥`A1`å’Œ`A2`的数æ®ç±»åž‹ ```{r} ## Check the data A1 A2 ## Check if they are identical identical(A1, A2) ``` 用户å¯ä»¥å°†`A2`当作一个普通的矩阵æ¥ä½¿ç”¨ã€‚如果需è¦åŒºåˆ†å…±äº«å¯¹è±¡çš„è¯ï¼Œå¯ä»¥ä½¿ç”¨`is.shared`函数 ```{r} ## Check if an object is shared is.shared(A1) is.shared(A2) ``` 我们知é“Ré‡Œé¢æœ‰è®¸å¤šå¹¶è¡Œè¿ç®—çš„package,例如`parallel`å’Œ`BiocParallel`ã€‚ä½ å¯ä»¥ä½¿ç”¨ä»»ä½•packageæ¥ä¼ 输共享对象`A2`,在下é¢çš„例å䏿ˆ‘们使用最基础的`parallel` packageæ¥ä¼ 输数æ®ã€‚ ```{r} library(parallel) ## Create a cluster with only 1 worker cl <- makeCluster(1) clusterExport(cl, "A2") ## Check if the object is still a shared object clusterEvalQ(cl, SharedObject::is.shared(A2)) stopCluster(cl) ``` å½“ä½ ä¼ è¾“ä¸€ä¸ªå…±äº«å¯¹è±¡çš„æ—¶å€™ï¼Œå®žé™…ä¸Šåªæœ‰å…±äº«å†…å˜çš„ç¼–å·ï¼Œè¿˜æœ‰ä¸€äº›R对象的信æ¯è¢«ä¼ 输过去了。我们å¯ä»¥é€šè¿‡`serialize`函数æ¥éªŒè¯è¿™ä¸€ç‚¹ ```{r} ## make a larger vector x1 <- rep(0, 10000) x2 <- share(x1) ## This is the actual data that will ## be sent to the other R workers data1 <-serialize(x1, NULL) data2 <-serialize(x2, NULL) ## Check the size of the data length(data1) length(data2) ``` é€šè¿‡æŸ¥çœ‹è¢«ä¼ è¾“çš„æ•°æ®ï¼Œæˆ‘们å¯ä»¥çœ‹åˆ°`x2`是明显å°äºŽ`x1`的。当其他R进程接å—到数æ®åŽï¼Œä»–们并ä¸ä¼šä¸º`x2`的数æ®åˆ†é…内å˜ï¼Œè€Œæ˜¯é€šè¿‡å…±äº«å†…å˜çš„ç¼–å·æ¥ç›´æŽ¥è¯»å–`x2`æ•°æ®ã€‚å› æ¤ï¼Œå†…å˜ä½¿ç”¨é‡ä¼šæ˜Žæ˜¾å‡å°‘。 ## 创建空的共享对象 å’Œ`vector`å‡½æ•°ç›¸ä¼¼ï¼Œä½ ä¹Ÿå¯ä»¥ç›´æŽ¥åˆ›å»ºä¸€ä¸ªç©ºçš„共享对象 ```{r} SharedObject(mode = "integer", length = 6) ``` 在创建共享对象过程ä¸ï¼Œä½ å¯ä»¥å°†å¯¹è±¡çš„attributes直接给出 ```{r} SharedObject(mode = "integer", length = 6, attrib = list(dim = c(2L, 3L))) ``` 如果需è¦äº†è§£æ›´å¤šç»†èŠ‚ï¼Œè¯·å‚考`?SharedObject` ## 共享对象的属性 å…±äº«å¯¹è±¡çš„å†…éƒ¨ç»“æž„é‡Œé¢æœ‰è®¸å¤šå±žæ€§ï¼Œä½ å¯ä»¥ç›´æŽ¥é€šè¿‡`sharedObjectProperties`æ¥æŸ¥çœ‹å®ƒä»¬ ```{r} ## get a summary report sharedObjectProperties(A2) ``` `dataId`是共享内å˜çš„ç¼–å·, `length`是共享对象的长度, `totalSize`是共享对象的大å°, `dataType`是共享对象的数æ®ç±»åž‹, `ownData`决定了是å¦åœ¨å½“å‰è¿›ç¨‹å†…共享对象ä¸éœ€è¦ä½¿ç”¨çš„æ—¶å€™å›žæ”¶å…±äº«å†…å˜. `copyOnWrite`,`sharedSubset`å’Œ`sharedCopy` 决定了共享对象数æ®å†™å…¥ï¼Œå–å集,和å¤åˆ¶æ—¶å€™çš„行为. 我们将会在`package默认设置`å’Œ`进阶教程`里é¢è¯¦ç»†è®¨è®ºè¿™ä¸‰ä¸ªå‚æ•°. éœ€è¦æ³¨æ„的是,大部分共享对象的属性是ä¸å¯å˜æ›´çš„, åªæœ‰ `copyOnWrite`,`sharedSubset`å’Œ`sharedCopy` 是å¯å˜çš„. ä½ å¯ä»¥é€šè¿‡`getCopyOnWrite`,`getSharedSubset`å’Œ`getSharedCopy` 去得到一个共享对象的属性,也å¯ä»¥é€šè¿‡`setCopyOnWrite`,`setSharedSubset`å’Œ`setSharedCopy`去设置他们 ```{r} ## get the individual properties getCopyOnWrite(A2) getSharedSubset(A2) getSharedCopy(A2) ## set the individual properties setCopyOnWrite(A2, FALSE) setSharedSubset(A2, TRUE) setSharedCopy(A2, TRUE) ## Check if the change has been made getCopyOnWrite(A2) getSharedSubset(A2) getSharedCopy(A2) ``` # 支æŒçš„æ•°æ®ç±»åž‹å’Œç»“æž„ 对于基础R类型æ¥è¯´ï¼Œ`SharedObject`支æŒ`raw`,`logical`,`integer`,`numeric`,`complex`å’Œ`character`. éœ€è¦æ³¨æ„的是,共享å—符串å‘é‡å¹¶ä¸ä¸€å®šèƒ½å¤Ÿä¿è¯å‡å°‘内å˜ä½¿ç”¨ï¼Œå› 为å—符串在R䏿œ‰è‡ªå·±çš„ç¼“å˜æ± ï¼Œæ‰€ä»¥åœ¨ä¼ è¾“å—符å‘é‡ä¸²çš„æ—¶å€™æˆ‘们ä»ç„¶éœ€è¦ä¼ 输å•个å—ç¬¦ä¸²ï¼Œå› æ¤å…±äº«å—符串å‘é‡åªæœ‰åœ¨å—符串é‡å¤æ¬¡æ•°æ¯”较多的时候会比较节约内å˜ã€‚å› ä¸ºå—符串å‘é‡çš„ç‰¹æ®Šæ€§ï¼Œä½ ä¹Ÿä¸èƒ½æŠŠå—符串å‘é‡é‡Œé¢çš„å—ç¬¦ä¸²æ›´æ”¹ä¸ºä¸€ä¸ªä»Žæ¥æ²¡æœ‰åœ¨å—符串å‘é‡é‡Œé¢å‡ºçŽ°è¿‡çš„å—符串。 对于容器类型,`SharedObject`支æŒ`list`,`pairlist`å’Œ`environment`。共享容器类型数æ®åªä¼šå°†å®¹å™¨å†…éƒ¨çš„å…ƒç´ å…±äº«ï¼Œå®¹å™¨æœ¬èº«å¹¶ä¸ä¼šè¢«å…±äº«ï¼Œå› æ¤ï¼Œå¦‚æžœä½ å°è¯•å‘å…±äº«å®¹å™¨é‡Œé¢æ·»åŠ æˆ–åˆ é™¤å…ƒç´ ï¼Œå…¶ä»–Rè¿›ç¨‹æ˜¯æ— æ³•è§‚æµ‹åˆ°ä½ çš„ä¿®æ”¹çš„ã€‚å› ä¸º`data.frame`本质上是一个`list`ï¼Œå› æ¤å®ƒä¹Ÿç¬¦åˆä¸Šè¿°è§„则。 对于S3å’ŒS4类型æ¥è¯´ï¼Œé€šå¸¸ä½ å¯ä»¥ç›´æŽ¥å…±äº«S3/S4对象的数æ®ã€‚å¦‚æžœä½ å¸Œæœ›å…±äº«çš„S3/S4对象éžå¸¸ç‰¹æ®Šï¼Œä¾‹å¦‚它需è¦è¯»å–ç£ç›˜æ•°æ®ï¼Œ`share`函数本身是一个S4çš„generic, ä½ å¯ä»¥é€šè¿‡é‡è½½å‡½æ•°æ¥å®šä¹‰ä½ 自己的共享方法。 如果一个对象的数æ®ç»“æž„å¹¶ä¸æ”¯æŒè¢«å…±äº«ï¼Œ`share`函数将会直接返回原本的对象。这åªä¼šåœ¨å¾ˆç‰¹æ®Šæƒ…况å‘ç”Ÿï¼Œå› ä¸º`SharedObject`包支æŒå¤§éƒ¨åˆ†æ•°æ®ç±»åž‹ã€‚å¦‚æžœä½ å¸Œæœ›åœ¨æ— æ³•å…±äº«çš„æƒ…å†µä¸‹è¿”å›žä¸€ä¸ªå¼‚å¸¸ï¼Œä½ å¯ä»¥åœ¨ä½¿ç”¨`share`æ—¶ä¼ å…¥å‚æ•°`mustWork = TRUE`。 ```{r} ## the element `A` is sharable and `B` is not x <- list(A = 1:3, B = as.symbol("x")) ## No error will be given, ## but the element `B` is not shared shared_x <- share(x) ## Use the `mustWork` argument ## An error will be given for the non-sharable object `B` tryCatch({ shared_x <- share(x, mustWork = TRUE) }, error=function(msg)message(msg$message) ) ``` å°±åƒæˆ‘们之å‰çœ‹åˆ°çš„ä¸€æ ·ï¼Œä½ å¯ä»¥ä½¿ç”¨`is.shared`åŽ»æŸ¥çœ‹ä¸€ä¸ªå¯¹è±¡æ˜¯å¦æ˜¯å…±äº«å¯¹è±¡ã€‚在默认的情况下,`is.shared`åªä¼šè¿”å›žä¸€ä¸ªé€»è¾‘å€¼ï¼Œå‘Šè¯‰ä½ è¿™ä¸ªå¯¹è±¡æœ¬èº«æ˜¯å¦è¢«å…±äº«äº†ï¼Œæˆ–者它å«è‡³å°‘ä¸€ä¸ªå…±äº«å¯¹è±¡ã€‚ä½ å¯ä»¥é€šè¿‡ä¼ å…¥`depth`傿•°æ¥çœ‹åˆ°å…·ä½“细节 ```{r} ## A single logical is returned is.shared(shared_x) ## Check each element in x is.shared(shared_x, depth = 1) ``` # Package默认设置 package默认设置控制ç€é»˜è®¤æƒ…å†µä¸‹çš„å…±äº«å¯¹è±¡çš„å±žæ€§ï¼Œä½ å¯ä»¥é€šè¿‡`sharedObjectPkgOptions`æ¥æŸ¥çœ‹å®ƒä»¬ ```{r} sharedObjectPkgOptions() ``` å°±åƒæˆ‘们之å‰è®¨è®ºçš„ä¸€æ ·ï¼Œ`mustWork = FALSE`æ„味ç€åœ¨é»˜è®¤æƒ…况下,当`share`函数é‡åˆ°ä¸ªä¸å¯å…±äº«çš„对象,它ä¸ä¼šæŠ›å‡ºä»»ä½•异常而是直接返回对象本身。`sharedSubset` å†³å®šäº†å½“ä½ å¯¹ä¸€ä¸ªå…±äº«å¯¹è±¡å–å集的时候,得到的åé›†æ˜¯å¦æ˜¯ä¸€ä¸ªå…±äº«å¯¹è±¡. `minLength`是共享对象最å°çš„长度,当一个对象的长度å°äºŽæœ€å°é•¿åº¦çš„æ—¶å€™ï¼Œå®ƒå°†ä¸ä¼šè¢«å…±äº«ã€‚ æˆ‘ä»¬ä¼šåœ¨è¿›é˜¶ç« èŠ‚é‡Œé¢è®¨è®º `copyOnWrite` å’Œ `sharedCopy`,ä¸è¿‡å¯¹äºŽå¤§éƒ¨åˆ†ç”¨æˆ·æ¥è¯´ï¼Œä½ å¹¶ä¸éœ€è¦å…³å¿ƒå®ƒä»¬ã€‚packageçš„å‚æ•°å¯ä»¥é€šè¿‡`sharedObjectPkgOptions`æ¥æ›´æ”¹ ```{r} ## change the default setting sharedObjectPkgOptions(mustWork = TRUE) ## Check if the change is made sharedObjectPkgOptions("mustWork") ## Restore the default sharedObjectPkgOptions(mustWork = FALSE) ``` éœ€è¦æ³¨æ„的是,`share`å‡½æ•°çš„å‚æ•°æœ‰ç€æ¯”package傿•°æ›´é«˜çš„ä¼˜å…ˆçº§ï¼Œå› æ¤ä½ å¯ä»¥é€šè¿‡å‘`share`å‡½æ•°æ·»åŠ å‚æ•°çš„æ–¹æ³•æ¥ä¸´æ—¶æ”¹å˜é»˜è®¤è®¾ç½®ã€‚ä¾‹å¦‚ï¼Œä½ å¯ä»¥é€šè¿‡`share(x, mustWork = TRUE)`æ¥å¿½ç•¥package的默认`mustWork`设置。 # 进阶教程 ## å†™æ—¶æ‹·è´ ç”±äºŽæ‰€æœ‰çš„R进程都会访问åŒä¸€ä¸ªå…±äº«å†…å˜çš„æ•°æ®ï¼Œå¦‚æžœåœ¨ä¸€ä¸ªè¿›ç¨‹ä¸æ›´æ”¹äº†å…±äº«å†…å˜çš„æ•°æ®ï¼Œå…¶ä»–进程的数æ®ä¹Ÿä¼šå—到影å“。为了防æ¢è¿™ç§æƒ…况的å‘生,当一个进程试图修改数æ®å†…容的时候,共享对象将会被å¤åˆ¶ã€‚举例æ¥è¯´ ```{r} x1 <- share(1:4) x2 <- x1 ## x2 becames a regular R object after the change is.shared(x2) x2[1] <- 10L is.shared(x2) ## x1 is not changed x1 x2 ``` 当我们å°è¯•修改`x2`的时候,R首先会å¤åˆ¶`x2`的数æ®ï¼Œç„¶åŽå†ä¿®æ”¹å®ƒçš„å€¼ã€‚å› æ¤ï¼Œè™½ç„¶`x1`å’Œ`x2`是åŒä¸€ä¸ªå…±äº«å¯¹è±¡ï¼Œå¯¹äºŽ`x2`的修改并ä¸ä¼šå½±å“`x1`的值。这个默认的行为å¯ä»¥é€šè¿‡`copyOnWrite`æ¥è¿›è¡Œæ›´æ”¹ ```{r} x1 <- share(1:4, copyOnWrite = FALSE) x2 <- x1 ## x2 will not be duplicated when a change is made is.shared(x2) x2[1] <- 0L is.shared(x2) ## x1 has been changed x1 x2 ``` 当我们手动把`copyOnWrite`å…³é—的时候,修改`x2`会导致`x1`ä¹Ÿè¢«ä¿®æ”¹äº†ã€‚è¿™ä¸ªå‚æ•°å¯ä»¥ç”¨äºŽå¹¶è¡Œè¿ç®—时写回数æ®ï¼Œä½ å¯ä»¥æå‰åˆ†é…好一个空的共享对象,关é—它的`copyOnWrite`,然åŽå°†å®ƒä¼ 给所有相关进程。当进程计算出结果åŽï¼Œç›´æŽ¥å°†æ•°æ®å†™å›žåˆ°å…±äº«å¯¹è±¡ä¸ï¼Œè¿™æ ·åå°±ä¸éœ€è¦é€šè¿‡ä¼ 统的数æ®ä¼ 输方å¼å°†ç»“æžœä¼ å›žç»™ä¸»è¿›ç¨‹äº†ã€‚ä¸è¿‡ï¼Œéœ€è¦æ³¨æ„的是,当我们关é—`copyOnWrite`çš„æ—¶å€™ï¼Œä½ å¯¹å…±äº«å¯¹è±¡çš„æ“作也å¯èƒ½å¯¼è‡´æ„外的结果。举例æ¥è¯´ ```{r} x <- share(1:4, copyOnWrite = FALSE) x -x x ``` 仅仅是对于负数的调用,就会导致`x`çš„å€¼è¢«æ›´æ”¹ã€‚å› æ¤ï¼Œç”¨æˆ·éœ€è¦å°å¿ƒä½¿ç”¨è¿™ä¸ªåŠŸèƒ½ã€‚å†™æ—¶æ‹·è´å¯ä»¥é€šè¿‡`share`函数的`copyOnWrite`傿•°æ¥è®¾ç½®ï¼Œä¹Ÿå¯ä»¥é€šè¿‡`setCopyOnwrite`å‡½æ•°éšæ—¶æ‰“å¼€æˆ–è€…å…³é— ```{r} ## Create x1 with copy-on-write off x1 <- share(1:4, copyOnWrite = FALSE) x2 <- x1 ## change the value of x2 x2[1] <- 0L ## Both x1 and x2 are affected x1 x2 ## Enable copy-on-write ## x2 is now independent with x1 setCopyOnWrite(x2, TRUE) x2[2] <- 0L ## only x2 is affected x1 x2 ``` ### è¦å‘Š å¦‚æžœä½ åœ¨å°è¯•修改共享对象的时候,将一个高精度的值赋给一个低精度的共享对象上,R会自动进行数æ®ç±»åž‹è½¬æ¢ï¼Œå°†ä½Žç²¾åº¦çš„共享对象å˜ä¸ºä¸€ä¸ªé«˜ç²¾åº¦çš„å¯¹è±¡ï¼Œå› æ¤ï¼Œä½ å®žé™…ä¸Šä¿®æ”¹çš„å°†æ˜¯é«˜ç²¾åº¦çš„æ™®é€šå¯¹è±¡è€Œä¸æ˜¯å…±äº«å¯¹è±¡ï¼Œå³ä¾¿ä½ 将写时拷è´å…³é—æŽ‰ï¼Œä½ å¯¹å®ƒçš„ä¿®æ”¹ä¹Ÿä¸ä¼šè¢«å…¶ä»–Rè¿›ç¨‹æ‰€å…±äº«ã€‚æ‰€ä»¥ï¼Œå½“ä½ å°è¯•ä¿®æ”¹ä¸€ä¸ªå…±äº«å¯¹è±¡æ—¶ï¼Œä½ éœ€è¦ç‰¹åˆ«å°å¿ƒå…±äº«å¯¹è±¡æ‰€ä½¿ç”¨çš„æ•°æ®ç±»åž‹ã€‚ ## å…±äº«æ‹·è´ `sharedCopy` 傿•°å†³å®šäº†ä¸€ä¸ªå…±äº«å¯¹è±¡çš„æ‹·è´æ˜¯å¦ä»ç„¶æ˜¯ä¸€ä¸ªå…±äº«å¯¹è±¡ã€‚举例æ¥è¯´ ```{r} x1 <- share(1:4) x2 <- x1 ## x2 is not shared after the duplication is.shared(x2) x2[1] <- 0L is.shared(x2) x1 <- share(1:4, sharedCopy = TRUE) x2 <- x1 ## x2 is still shared(but different from x1) ## after the duplication is.shared(x2) x2[1] <- 0L is.shared(x2) ``` 由于性能上的考虑,默认的设置为`sharedCopy=FALSE`,ä¸è¿‡ä½ å¯ä»¥éšæ—¶é€šè¿‡`setSharedCopy`æ¥æ›´æ”¹ä¸€ä¸ªå…±äº«å¯¹è±¡çš„è®¾ç½®ã€‚éœ€è¦æ³¨æ„的是,`sharedCopy`åªèƒ½å¤Ÿåœ¨`copyOnWrite = TRUE`的时候生效。 ## 列出共享内å˜ç¼–å· ä½ å¯ä»¥é€šè¿‡`listSharedObjects`函数æ¥åˆ—出所有的共享对象使用的共享内å˜ç¼–å· ```{r} listSharedObjects() ``` 对用户æ¥è¯´ï¼Œè¿™ä¸ªå‡½æ•°å¹¶ä¸ä¼šè¢«ç»å¸¸ä½¿ç”¨ï¼Œä¸è¿‡å¦‚æžœä½ é‡åˆ°äº†å…±äº«å†…å˜æ³„æ¼çš„é—®é¢˜ï¼Œä½ å¯ä»¥é€šè¿‡`freeSharedMemory(ID)`手动释放共享内å˜ã€‚ # 基于`SharedObject`å¼€å‘package 我们æä¾›äº†ä¸‰ä¸ªçº§åˆ«çš„函数库æ¥å¸®åЩ开å‘è€…å¼€å‘æ–°çš„package。 ## 用户API 开呿–°package最简å•的方法是通过é‡è½½`share`å‡½æ•°æ¥æ”¯æŒæ›´åŠ å¤šçš„æ•°æ®ç±»åž‹ã€‚我们推è基于已有的`share`功能æ¥å¼€å‘æ›´åŠ ä¸°å¯Œçš„åŠŸèƒ½ï¼Œè¿™æ ·`SharedObject`å°†ä¼šå¸®ä½ ç®¡ç†æ‰€æœ‰çš„共享内å˜ï¼Œä½ ä¸éœ€è¦æ‰‹åŠ¨ç®¡ç†å†…å˜çš„生命周期。 ## R的共享内å˜ç®¡ç†API å¦‚æžœä½ éœ€è¦æ‰‹åŠ¨ç®¡ç†å…±äº«å†…å˜ï¼Œä½ å¯ä»¥é€šè¿‡`SharedObject`ä¸æä¾›çš„`allocateSharedMemory`,`mapSharedMemory`,`unmapSharedMemory`,`freeSharedMemory`,`hasSharedMemory`å’Œ`getSharedMemorySize`æ¥è¿›è¡Œå†…å˜çš„申请和释放. éœ€è¦æ³¨æ„çš„äº‹ï¼Œå¦‚æžœä½ æ‰‹åŠ¨ç”³è¯·äº†ä¸€ä¸ªå…±äº«å†…å˜ï¼Œåœ¨ä½ 使用åŽä½ éœ€è¦æ‰‹åŠ¨é‡Šæ”¾å®ƒï¼Œå¦åˆ™å°†ä¼šå¯¼è‡´å†…å˜æ³„æ¼ã€‚ ## C++的共享内å˜ç®¡ç†API å¦‚æžœä½ éœ€è¦ä½¿ç”¨C++å¼€å‘packageï¼Œä½ å¯èƒ½éœ€è¦ä½¿ç”¨C++函数去管ç†å…±äº«å†…å˜ã€‚`SharedObject`䏿‰€æœ‰çš„åŠŸèƒ½ä½ éƒ½å¯ä»¥é€šè¿‡package里é¢çš„C++函数æ¥åšåˆ°ã€‚䏋颿˜¯å…³äºŽå¦‚何链接和使用`SharedObject`ä¸C++ API的教程。 ### ç¬¬ä¸€æ¥ ä¸ºäº†ä½¿ç”¨C++ APIï¼Œä½ éœ€è¦å°†`SharedObject`æ·»åŠ è¿›DESCRIPTION文件ä¸çš„LinkingToæ¡ç›®é‡Œé¢ ``` LinkingTo: SharedObject ``` ### ç¬¬äºŒæ¥ åœ¨ä½ çš„C++文件里,引用`SharedObject`的头文件`#include "SharedObject/sharedMemory.h"`。 ### ç¬¬ä¸‰æ¥ ä¸ºäº†ç¼–è¯‘å’Œé“¾æŽ¥ä½ çš„package, ä½ éœ€è¦åœ¨srcç›®å½•ä¸‹æ·»åŠ ä¸ªMakevars文件 ``` SHARED_OBJECT_LIBS = $(shell echo 'SharedObject:::pkgconfig("PKG_LIBS")'|\ "${R_HOME}/bin/R" --vanilla --slave) SHARED_OBJECT_CPPFLAGS = $(shell echo 'SharedObject:::pkgconfig("PKG_CPPFLAGS")'|\ "${R_HOME}/bin/R" --vanilla --slave) PKG_LIBS := $(PKG_LIBS) $(SHARED_OBJECT_LIBS) PKG_CPPFLAGS := $(PKG_CPPFLAGS) $(SHARED_OBJECT_CPPFLAGS) ``` éœ€è¦æ³¨æ„的是`$(shell ...)`是个GNU makeè¯æ³•ï¼Œå› æ¤ä½ ä¹Ÿéœ€è¦æŠŠGNU makeæ·»åŠ è¿›DESCRIPTION文件ä¸SystemRequirementsæ¡ç›® ``` SystemRequirements: GNU make ``` ä½ å¯ä»¥åœ¨`SharedObject`çš„å¤´æ–‡ä»¶ä¸æ‰¾åˆ°å…³äºŽå®ƒC++ API的使用说明。 # Session Information ```{r} sessionInfo() ```