--- 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() ```