├── .Rbuildignore ├── .Rinstignore ├── .github ├── .gitignore ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ └── feature_request.md └── workflows │ ├── R-CMD-check.yaml │ ├── future_tests.yaml │ ├── revdepcheck-top.yaml │ ├── rhub.yaml │ ├── test-coverage.yaml │ └── tmate.yaml ├── .gitignore ├── .make └── Makefile ├── CONDUCT.md ├── CONTRIBUTING.md ├── DESCRIPTION ├── Makefile ├── NAMESPACE ├── NEWS.md ├── R ├── 000.bquote.R ├── 000.import.R ├── 000.re-exports.R ├── 010.tweakable.R ├── 010.utils-parallelly.R ├── backend_api-01-FutureBackend-class.R ├── backend_api-03.MultiprocessFutureBackend-class.R ├── backend_api-11.ClusterFutureBackend-class.R ├── backend_api-11.MulticoreFutureBackend-class.R ├── backend_api-11.SequentialFutureBackend-class.R ├── backend_api-13.MultisessionFutureBackend-class.R ├── backend_api-ConstantFuture-class.R ├── backend_api-Future-class.R ├── backend_api-FutureRegistry.R ├── backend_api-UniprocessFuture-class.R ├── backend_api-evalFuture.R ├── core_api-cancel.R ├── core_api-future.R ├── core_api-reset.R ├── core_api-resolved.R ├── core_api-value.R ├── delayed_api-futureAssign.R ├── delayed_api-futureOf.R ├── demo_api-mandelbrot.R ├── infix_api-01-futureAssign_OP.R ├── infix_api-02-globals_OP.R ├── infix_api-03-seed_OP.R ├── infix_api-04-stdout_OP.R ├── infix_api-05-conditions_OP.R ├── infix_api-06-lazy_OP.R ├── infix_api-07-label_OP.R ├── infix_api-08-plan_OP.R ├── infix_api-09-tweak_OP.R ├── protected_api-FutureCondition-class.R ├── protected_api-FutureGlobals-class.R ├── protected_api-FutureResult-class.R ├── protected_api-futures.R ├── protected_api-globals.R ├── protected_api-journal.R ├── protected_api-resolve.R ├── protected_api-signalConditions.R ├── testme.R ├── utils-basic.R ├── utils-conditions.R ├── utils-connections.R ├── utils-debug.R ├── utils-immediateCondition.R ├── utils-marshalling.R ├── utils-objectSize.R ├── utils-options.R ├── utils-prune_pkg_code.R ├── utils-registerClusterTypes.R ├── utils-rng_utils.R ├── utils-signalEarly.R ├── utils-stealth_sample.R ├── utils-sticky_globals.R ├── utils-tweakExpression.R ├── utils-uuid.R ├── utils-whichIndex.R ├── utils_api-backtrace.R ├── utils_api-capture_journals.R ├── utils_api-futureCall.R ├── utils_api-futureSessionInfo.R ├── utils_api-makeClusterFuture.R ├── utils_api-minifuture.R ├── utils_api-nbrOfWorkers.R ├── utils_api-plan-with.R ├── utils_api-plan.R ├── utils_api-sessionDetails.R ├── utils_api-tweak.R └── zzz.R ├── README.md ├── README_ja.md ├── cran-comments.md ├── demo ├── 00Index ├── fibonacci.R └── mandelbrot.R ├── incl ├── OVERVIEW.md ├── as_lecyer_cmrg_seed.R ├── capture_journals.R ├── cluster.R ├── future.R ├── futureCall.R ├── futureOf.R ├── futureSessionInfo.R ├── journal.R ├── mandelbrot.R ├── multicore.R ├── multisession.R ├── nbrOfWorkers.R ├── plan.R ├── reset.R ├── sequential.R ├── value.R └── with.R ├── inst ├── CITATION ├── WORDLIST ├── testme │ ├── _epilogue │ │ ├── 001.undo-future.R │ │ ├── 002.undo-state.R │ │ ├── 090.gc.R │ │ ├── 099.session_info.R │ │ ├── 995.detritus-connections.R │ │ └── 999.detritus-files.R │ ├── _prologue │ │ ├── 001.load.R │ │ ├── 002.record-state.R │ │ ├── 030.imports.R │ │ ├── 050.utils.R │ │ ├── 090.context.R │ │ ├── 090.options.R │ │ ├── 091.envvars.R │ │ ├── 099.future-setup.R │ │ └── 995.detrius-connections.R │ ├── deploy.R │ ├── run.R │ ├── test-000.R │ ├── test-FutureError.R │ ├── test-FutureGlobals.R │ ├── test-FutureRegistry.R │ ├── test-adhoc_native_to_utf8.R │ ├── test-backtrace.R │ ├── test-bquote.R │ ├── test-cancel.R │ ├── test-capture_journals.R │ ├── test-cluster,worker-termination.R │ ├── test-cluster-connection-clashes.R │ ├── test-cluster-missing-future-pkg.R │ ├── test-demo-fibonacci.R │ ├── test-demo-mandelbrot.R │ ├── test-dotdotdot.R │ ├── test-early-signaling.R │ ├── test-error_on_warn_2.R │ ├── test-future,labels.R │ ├── test-future,optsenvvars.R │ ├── test-future.R │ ├── test-futureAssign.R │ ├── test-futureAssign_OP.R │ ├── test-futureAssign_OP_with_environment.R │ ├── test-futureAssign_OP_with_listenv.R │ ├── test-futureCall.R │ ├── test-futureOf.R │ ├── test-futureOf_with_environment.R │ ├── test-futureOf_with_listenv.R │ ├── test-futureSessionInfo.R │ ├── test-futures.R │ ├── test-globals,NSE.R │ ├── test-globals,S4methods.R │ ├── test-globals,formulas.R │ ├── test-globals,locals.R │ ├── test-globals,manual.R │ ├── test-globals,packages.R │ ├── test-globals,resolve.R │ ├── test-globals,subassignment.R │ ├── test-globals,toolarge.R │ ├── test-globals,tricky.R │ ├── test-globals,tricky2.R │ ├── test-globals,tricky_recursive.R │ ├── test-globalsOf,tweaks.R │ ├── test-immediateCondition.R │ ├── test-interrupts-from-worker-itself.R │ ├── test-invalid-owner.R │ ├── test-makeClusterFuture.R │ ├── test-mandelbrot.R │ ├── test-misuse-connections.R │ ├── test-mpi.R │ ├── test-multicore,multithreading.R │ ├── test-multicore,worker-termination.R │ ├── test-multisession-libpaths.R │ ├── test-nbrOfWorkers.R │ ├── test-nested_futures,mc.cores.R │ ├── test-nested_futures.R │ ├── test-non-exportable,connections.R │ ├── test-objectSize.R │ ├── test-plan.R │ ├── test-relaying,muffle.R │ ├── test-relaying,split.R │ ├── test-relaying.R │ ├── test-requestCore.R │ ├── test-requestNode.R │ ├── test-reserved-keyword-functions.R │ ├── test-reset.R │ ├── test-resolve.R │ ├── test-resolved-non-blocking-test.R │ ├── test-rng.R │ ├── test-rng_utils.R │ ├── test-sequential.R │ ├── test-sessionDetails.R │ ├── test-startup-onAttach.R │ ├── test-startup-onLoad.R │ ├── test-startup-parseCmdArgs.R │ ├── test-stdout.R │ ├── test-timeouts.R │ ├── test-tweak.R │ ├── test-utils.R │ ├── test-uuid.R │ ├── test-value-error-cancels-set.R │ ├── test-value.R │ └── test-whichIndex.R └── vignettes-static │ ├── future-1-overview.md.rsp.rsp │ └── incl │ ├── future-1-overview-example2.R │ └── future-1-overview-example3.R ├── man ├── Future-class.Rd ├── FutureBackend.Rd ├── FutureCondition.Rd ├── FutureGlobals.Rd ├── FutureResult.Rd ├── MulticoreFuture-class.Rd ├── MultiprocessFuture-class.Rd ├── UniprocessFuture-class.Rd ├── backtrace.Rd ├── cancel.Rd ├── cluster.Rd ├── clusterExportSticky.Rd ├── figures │ └── logo.png ├── find_references.Rd ├── future.Rd ├── futureAssign.Rd ├── futureOf.Rd ├── futureSessionInfo.Rd ├── futures.Rd ├── getExpression.Rd ├── getGlobalsAndPackages.Rd ├── makeClusterFuture.Rd ├── mandelbrot.Rd ├── multicore.Rd ├── multisession.Rd ├── nbrOfWorkers.Rd ├── nullcon.Rd ├── plan.Rd ├── private_length.Rd ├── re-exports.Rd ├── readImmediateConditions.Rd ├── requestCore.Rd ├── reset.Rd ├── resetWorkers.Rd ├── resolve.Rd ├── resolved.Rd ├── result.Rd ├── run.Rd ├── save_rds.Rd ├── sequential.Rd ├── sessionDetails.Rd ├── signalConditions.Rd ├── sticky_globals.Rd ├── usedCores.Rd ├── value.Rd └── zzz-future.options.Rd ├── pkgdown ├── _pkgdown.yml ├── _pkgdown.yml.rsp └── favicon │ ├── apple-touch-icon-120x120.png │ ├── apple-touch-icon-60x60.png │ ├── apple-touch-icon-76x76.png │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ └── favicon.ico ├── revdep ├── DESCRIPTION ├── README.md ├── R_FUTURE_CONNECTIONS_ONMISUSE=error │ ├── README.md │ ├── cran.md │ ├── failures.md │ ├── notes.md │ └── problems.md ├── R_FUTURE_GLOBALS_ONREFERENCE=error │ ├── README.md │ ├── cran.md │ ├── failures.md │ └── problems.md ├── R_FUTURE_PLAN=multisession │ ├── README.md │ ├── cran.md │ ├── failures.md │ └── problems.md ├── R_FUTURE_RESOLVED_TIMEOUT=0 │ ├── README.md │ ├── cran.md │ ├── failures.md │ ├── notes.md │ └── problems.md ├── cran.md ├── failures.md ├── notes.md ├── problems.md ├── revdepcheck.Renviron ├── run.R ├── run.pbs └── run.sge ├── tests ├── test-000.R ├── test-FutureError.R ├── test-FutureGlobals.R ├── test-FutureRegistry.R ├── test-adhoc_native_to_utf8.R ├── test-backtrace.R ├── test-bquote.R ├── test-cancel.R ├── test-capture_journals.R ├── test-cluster,worker-termination.R ├── test-cluster-connection-clashes.R ├── test-cluster-missing-future-pkg.R ├── test-demo-fibonacci.R ├── test-demo-mandelbrot.R ├── test-dotdotdot.R ├── test-early-signaling.R ├── test-error_on_warn_2.R ├── test-future,labels.R ├── test-future,optsenvvars.R ├── test-future.R ├── test-futureAssign.R ├── test-futureAssign_OP.R ├── test-futureAssign_OP_with_environment.R ├── test-futureAssign_OP_with_listenv.R ├── test-futureCall.R ├── test-futureOf.R ├── test-futureOf_with_environment.R ├── test-futureOf_with_listenv.R ├── test-futureSessionInfo.R ├── test-futures.R ├── test-globals,NSE.R ├── test-globals,S4methods.R ├── test-globals,formulas.R ├── test-globals,locals.R ├── test-globals,manual.R ├── test-globals,packages.R ├── test-globals,resolve.R ├── test-globals,subassignment.R ├── test-globals,toolarge.R ├── test-globals,tricky.R ├── test-globals,tricky2.R ├── test-globals,tricky_recursive.R ├── test-globalsOf,tweaks.R ├── test-immediateCondition.R ├── test-interrupts-from-worker-itself.R ├── test-invalid-owner.R ├── test-makeClusterFuture.R ├── test-mandelbrot.R ├── test-misuse-connections.R ├── test-mpi.R ├── test-multicore,multithreading.R ├── test-multicore,worker-termination.R ├── test-multisession-libpaths.R ├── test-nbrOfWorkers.R ├── test-nested_futures,mc.cores.R ├── test-nested_futures.R ├── test-non-exportable,connections.R ├── test-objectSize.R ├── test-plan.R ├── test-relaying,muffle.R ├── test-relaying,split.R ├── test-relaying.R ├── test-requestCore.R ├── test-requestNode.R ├── test-reserved-keyword-functions.R ├── test-reset.R ├── test-resolve.R ├── test-resolved-non-blocking-test.R ├── test-rng.R ├── test-rng_utils.R ├── test-sequential.R ├── test-sessionDetails.R ├── test-startup-onAttach.R ├── test-startup-onLoad.R ├── test-startup-parseCmdArgs.R ├── test-stdout.R ├── test-timeouts.R ├── test-tweak.R ├── test-utils.R ├── test-uuid.R ├── test-value-error-cancels-set.R ├── test-value.R └── test-whichIndex.R └── vignettes ├── future-1-overview.md.rsp ├── future-2-output.md.rsp ├── future-2b-backend.md.rsp ├── future-3-topologies.md.rsp ├── future-4-issues.md.rsp ├── future-4-non-exportable-objects.md.rsp ├── future-5-startup.md.rsp ├── future-6-future-api-backend-specification.md.rsp ├── future-7-for-package-developers.md.rsp └── future-8-how-future-is-validated.md.rsp /.Rbuildignore: -------------------------------------------------------------------------------- 1 | #---------------------------- 2 | # Git and SVN related 3 | #---------------------------- 4 | ^.svn 5 | ^.git 6 | ^.make 7 | ^INSTALL[.]md$ 8 | ^OVERVIEW[.]md$ 9 | ^README.*[.]md$ 10 | ^CONDUCT[.]md$ 11 | ^CONTRIBUTING[.]md$ 12 | ^docs 13 | ^pkgdown 14 | 15 | #---------------------------- 16 | # devtools 17 | #---------------------------- 18 | revdep 19 | 20 | #---------------------------- 21 | # Travis-CI et al. 22 | #---------------------------- 23 | ^[.]travis[.]yml$ 24 | ^travis-tool[.]sh$ 25 | ^pkg-build[.]sh$ 26 | ^appveyor[.]yml$ 27 | ^covr-utils.R$ 28 | ^[.]covr[.]R$ 29 | ^[.]covr[.]rds$ 30 | 31 | #---------------------------- 32 | # R related 33 | #---------------------------- 34 | Rplots.pdf$ 35 | ^cran-comments[.].*$ 36 | ^vignettes/.*[.](pdf|PDF)$ 37 | ^vignettes/.*[.](r|R)$ 38 | ^vignettes/[.]install_extras$ 39 | ^Makefile$ 40 | ^incl 41 | ^NAMESPACE,.*[.]txt$ 42 | ^nohup.*$ 43 | ^[.]R 44 | ^[.]benchmark 45 | ^[.]devel 46 | ^[.]test 47 | ^[.]check 48 | ^[.]local 49 | ^.*[.]tar[.]gz$ 50 | 51 | #---------------------------- 52 | # Package specific 53 | #---------------------------- 54 | ^[.]BatchJobs[.]R$ 55 | ^[.]future 56 | 57 | #---------------------------- 58 | # Miscellaneous 59 | #---------------------------- 60 | ^.ghi 61 | ^.issues 62 | ^last.dump* 63 | [.]Rdump 64 | -------------------------------------------------------------------------------- /.Rinstignore: -------------------------------------------------------------------------------- 1 | # Certain LaTeX files (e.g. bib, bst, sty) must be part of the build 2 | # such that they are available for R CMD check. These are excluded 3 | # from the install using .Rinstignore in the top-level directory 4 | # such as this one. 5 | doc/.*[.](bib|bst|sty)$ 6 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve (Please use future's 'Discussions' for Q&A) 4 | title: '' 5 | labels: 'bug' 6 | assignees: '' 7 | 8 | --- 9 | (Please use for Q&A) 10 | 11 | 12 | **Describe the bug** 13 | 14 | A clear and concise description of what the bug is. 15 | 16 | 17 | **Reproduce example** 18 | 19 | A reproducible example using R code. 20 | 21 | Please format your inline code and code blocks using Markdown (). 22 | 23 | 24 | **Expected behavior** 25 | 26 | A clear and concise description of what you expected to happen. 27 | 28 | 29 | **Session information** 30 | 31 | Please share your session information *after* the error has occurred so that we also see which packages and versions are involved; 32 | 33 | ```r 34 | > sessionInfo() 35 | … 36 | > future::futureSessionInfo() 37 | … 38 | ``` 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | lank_issues_enabled: true 2 | contact_links: 3 | - name: Support & Discussions 4 | url: https://github.com/futureverse/future/discussions/ 5 | about: Got a question? Something is not working? Want to share an idea? 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project (Please use future's 'Discussions' for Q&A) 4 | title: '' 5 | labels: 'feature request' 6 | assignees: '' 7 | 8 | --- 9 | (Please use for Q&A) 10 | 11 | **Wish or feature request** 12 | 13 | A clear and concise description of what the problem is. For example, I would like to be able to ... 14 | 15 | Please format your inline code and code blocks using Markdown (). 16 | 17 | -------------------------------------------------------------------------------- /.github/workflows/test-coverage.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_dispatch: # Enables manual triggering 3 | 4 | name: test-coverage.yaml 5 | 6 | permissions: read-all 7 | 8 | jobs: 9 | test-coverage: 10 | runs-on: ubuntu-latest 11 | env: 12 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | 17 | - name: Assert CODECOV_TOKEN is set 18 | run: | 19 | if [[ -z "${{secrets.CODECOV_TOKEN}}" ]]; then 20 | >&2 echo "::error::ERROR: 'secrets.CODECOV_TOKEN' not set" 21 | exit 1 22 | fi 23 | 24 | - uses: r-lib/actions/setup-r@v2 25 | with: 26 | use-public-rspm: true 27 | 28 | - uses: r-lib/actions/setup-r-dependencies@v2 29 | with: 30 | extra-packages: any::covr, any::xml2 31 | needs: coverage 32 | 33 | - name: Install itself 34 | run: | 35 | install.packages(".", repos = NULL, type = "source") 36 | shell: Rscript {0} 37 | 38 | - name: Test coverage 39 | run: | 40 | cov <- covr::package_coverage( 41 | quiet = FALSE, 42 | clean = FALSE, 43 | install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package") 44 | ) 45 | print(cov) 46 | covr::to_cobertura(cov) 47 | shell: Rscript {0} 48 | 49 | - uses: codecov/codecov-action@v4 50 | with: 51 | fail_ci_if_error: ${{ github.event_name != 'pull_request' && true || false }} 52 | file: ./cobertura.xml 53 | plugin: noop 54 | disable_search: true 55 | token: ${{ secrets.CODECOV_TOKEN }} 56 | 57 | - name: Upload test results 58 | if: failure() 59 | uses: actions/upload-artifact@v4 60 | with: 61 | name: coverage-test-failures 62 | path: ${{ runner.temp }}/package 63 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rhistory 2 | *~ 3 | **/*~ 4 | .R 5 | .benchmark 6 | .check 7 | .devel 8 | .test 9 | *.o 10 | *.dll 11 | *.Rout 12 | .RData 13 | *.Rproj* 14 | *.swp 15 | .covr.rds 16 | .future 17 | .ghi 18 | .issues 19 | .make 20 | .local 21 | docs/ 22 | revdep/data.sqlite 23 | revdep/checks/* 24 | revdep/library/* 25 | .Rdump 26 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 2 | # Contributing to the 'future' package 3 | 4 | This Git repository uses the [Git Flow](https://nvie.com/posts/a-successful-git-branching-model/) branching model (the [`git flow`](https://github.com/petervanderdoes/gitflow-avh) extension is useful for this). The [`develop`](https://github.com/futureverse/future/tree/develop) branch contains the latest contributions and other code that will appear in the next release, and the [`master`](https://github.com/futureverse/future) branch contains the code of the latest release, which is exactly what is currently on [CRAN](https://cran.r-project.org/package=future). 5 | 6 | Contributing to this package is easy. Just send a [pull request](https://help.github.com/articles/using-pull-requests/). When you send your PR, make sure `develop` is the destination branch on the [future repository](https://github.com/futureverse/future). Your PR should pass `R CMD check --as-cran`, which will also be checked by GitHub Actions and when the PR is submitted. 7 | 8 | We abide to the [Code of Conduct](https://www.contributor-covenant.org/version/2/0/code_of_conduct/) of Contributor Covenant. 9 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: future 2 | Version: 1.58.0-9000 3 | Title: Unified Parallel and Distributed Processing in R for Everyone 4 | Depends: 5 | R (>= 3.2.0) 6 | Imports: 7 | digest, 8 | globals (>= 0.18.0), 9 | listenv (>= 0.8.0), 10 | parallel, 11 | parallelly (>= 1.44.0), 12 | utils 13 | Suggests: 14 | methods, 15 | RhpcBLASctl, 16 | R.rsp, 17 | markdown 18 | VignetteBuilder: R.rsp 19 | Authors@R: c(person("Henrik", "Bengtsson", 20 | role = c("aut", "cre", "cph"), 21 | email = "henrikb@braju.com", 22 | comment = c(ORCID = "0000-0002-7579-5165"))) 23 | Description: The purpose of this package is to provide a lightweight and 24 | unified Future API for sequential and parallel processing of R 25 | expression via futures. The simplest way to evaluate an expression 26 | in parallel is to use `x %<-% { expression }` with `plan(multisession)`. 27 | This package implements sequential, multicore, multisession, and 28 | cluster futures. With these, R expressions can be evaluated on the 29 | local machine, in parallel a set of local machines, or distributed 30 | on a mix of local and remote machines. 31 | Extensions to this package implement additional backends for 32 | processing futures via compute cluster schedulers, etc. 33 | Because of its unified API, there is no need to modify any code in order 34 | switch from sequential on the local machine to, say, distributed 35 | processing on a remote compute cluster. 36 | Another strength of this package is that global variables and functions 37 | are automatically identified and exported as needed, making it 38 | straightforward to tweak existing code to make use of futures. 39 | License: LGPL (>= 2.1) 40 | LazyLoad: TRUE 41 | ByteCompile: TRUE 42 | URL: https://future.futureverse.org, https://github.com/futureverse/future 43 | BugReports: https://github.com/futureverse/future/issues 44 | Language: en-US 45 | Encoding: UTF-8 46 | RoxygenNote: 7.3.2 47 | Roxygen: list(markdown = TRUE) 48 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include .make/Makefile 2 | 3 | vignettes/future-1-overview.md.rsp: inst/vignettes-static/future-1-overview.md.rsp.rsp 4 | $(CD) $(@D); \ 5 | $(R_SCRIPT) -e "R.rsp::rfile" ../$< --postprocess=FALSE 6 | $(RM) README.md 7 | $(MAKE) README.md 8 | 9 | vignettes: vignettes/future-1-overview.md.rsp 10 | 11 | spelling: 12 | $(R_SCRIPT) -e "spelling::spell_check_package()" 13 | $(R_SCRIPT) -e "spelling::spell_check_files(c('NEWS.md', 'inst/vignettes-static/future-1-overview.md.rsp.rsp', dir('vignettes', pattern='[.]rsp$$', full.names=TRUE)), ignore=readLines('inst/WORDLIST', warn=FALSE))" 14 | 15 | future.tests/%: 16 | $(R_SCRIPT) -e "future.tests::check" --args --test-plan=$* 17 | 18 | future.tests_future.mirai: future.tests/future.mirai\:\:mirai_multisession future.tests/future.mirai\:\:mirai_cluster 19 | 20 | future.tests_future.callr: future.tests/future.callr\:\:callr 21 | 22 | future.tests_future.batchtools: future.tests/future.batchtools\:\:batchtools_local 23 | 24 | future.tests_built_in: future.tests/sequential future.tests/multicore future.tests/multisession future.tests/cluster 25 | 26 | future.tests: future.tests_built_in 27 | -------------------------------------------------------------------------------- /R/000.import.R: -------------------------------------------------------------------------------- 1 | import_from <- function(name, mode = "function", default = NULL, package) { 2 | ns <- getNamespace(package) 3 | if (exists(name, mode = mode, envir = ns, inherits = FALSE)) { 4 | get(name, mode = mode, envir = ns, inherits = FALSE) 5 | } else if (!is.null(default)) { 6 | default 7 | } else { 8 | stop(sprintf("No such '%s' %s: %s()", package, mode, name)) 9 | } 10 | } 11 | 12 | import_parallelly <- function(...) { 13 | import_from(..., package = "parallelly") 14 | } 15 | 16 | import_parallel <- function(...) { 17 | import_from(..., package = "parallel") 18 | } 19 | 20 | import_parallel_fcn <- function(name, ...) { 21 | import_from(name, ..., default = function(...) { 22 | stop(sprintf("No such function: parallel:::%s()", name)) 23 | }, package = "parallel") 24 | } 25 | 26 | ## We are currently importing the following non-exported functions: 27 | ## * cluster futures: 28 | ## - parallel:::defaultCluster() ## non-critical / not really needed / 29 | ## ## can be dropped in R (>= 3.5.0) 30 | ## - parallel:::closeNode() ## non-critical / 31 | ## ## can be dropped in R (>= 4.4.0) 32 | ## - parallel:::sendCall() ## run() 33 | ## - parallel:::recvData() ## can be dropped in R (>= 4.4.0) 34 | ## * multicore futures: 35 | ## - parallel:::selectChildren() ## resolved() 36 | ## - parallel:::rmChild() ## value() 37 | ## As well as the following ones (because they are not exported on Windows): 38 | ## * multicore futures: 39 | ## - parallel::mcparallel() ## run() 40 | ## - parallel::mccollect() ## value() 41 | importParallel <- import_parallelly("importParallel") 42 | -------------------------------------------------------------------------------- /R/010.tweakable.R: -------------------------------------------------------------------------------- 1 | argnames <- function(..., exclude = "...") { 2 | fcns <- list(...) 3 | names <- lapply(fcns, FUN = function(fcn) { 4 | names(formals(fcn)) 5 | }) 6 | names <- unlist(names, use.names = FALSE) 7 | names <- unique(names) 8 | names <- setdiff(names, exclude) 9 | } 10 | 11 | tweakable <- function(x, ...) { 12 | attr(x, "tweakable", exact = TRUE) 13 | } 14 | 15 | untweakable <- function(x, ...) { 16 | attr(x, "untweakable", exact = TRUE) 17 | } 18 | 19 | `tweakable<-` <- function(x, value) { 20 | if (is.function(value)) { 21 | value <- list(value) 22 | } 23 | names <- names(formals(x)) 24 | 25 | for (kk in seq_along(value)) { 26 | obj <- value[[kk]] 27 | if (is.character(obj)) { 28 | names <- c(names, obj) 29 | } else { 30 | names <- c(names, tweakable(obj)) 31 | } 32 | } 33 | names <- setdiff(names, "...") 34 | 35 | names <- setdiff(names, untweakable(x)) 36 | for (kk in seq_along(value)) { 37 | obj <- value[[kk]] 38 | if (is.character(obj)) { 39 | names <- setdiff(names, obj) 40 | } else { 41 | names <- setdiff(names, untweakable(obj)) 42 | } 43 | } 44 | names <- unique(names) 45 | attr(x, "tweakable") <- names 46 | invisible(x) 47 | } 48 | 49 | `untweakable<-` <- function(x, value) { 50 | attr(x, "untweakable") <- unique(value) 51 | invisible(x) 52 | } 53 | -------------------------------------------------------------------------------- /R/010.utils-parallelly.R: -------------------------------------------------------------------------------- 1 | #' @importFrom parallelly makeClusterPSOCK makeNodePSOCK 2 | makeClusterPSOCK_args <- local({ 3 | .args <- NULL 4 | 5 | function() { 6 | if (is.null(.args)) { 7 | ## Arguments meant for makeClusterPSOCK() and makeNodePSOCK() 8 | args <- character(0L) 9 | for (name in c("makeClusterPSOCK", "makeNodePSOCK")) { 10 | if (!exists(name, mode = "function")) next 11 | fcn <- get(name, mode = "function") 12 | args <- c(args, names(formals(fcn))) 13 | } 14 | args <- unique(args) 15 | args <- setdiff(args, "...") 16 | .args <<- args 17 | } 18 | .args 19 | } 20 | }) 21 | -------------------------------------------------------------------------------- /R/backend_api-ConstantFuture-class.R: -------------------------------------------------------------------------------- 1 | # Used by getGlobalsAndPackages() 2 | ConstantFuture <- function(..., globals = NULL, packages = NULL, stdout = NA, conditions = NULL, seed = NULL, lazy = FALSE, envir = emptyenv()) { 3 | future <- Future(..., NULL, packages = NULL, stdout = NA, conditions = NULL, seed = NULL, lazy = FALSE, envir = envir) 4 | t_start <- Sys.time() 5 | future[["result"]] <- FutureResult( 6 | value = eval(future[["expr"]], envir = envir), 7 | seed = seed, 8 | started = t_start, 9 | finished = t_start 10 | ) 11 | future[["state"]] <- "finished" 12 | future <- structure(future, class = c("ConstantFuture", class(future))) 13 | future 14 | } 15 | 16 | #' @export 17 | run.ConstantFuture <- function(future, ...) { 18 | future 19 | } 20 | 21 | #' @export 22 | result.ConstantFuture <- function(future, ...) { 23 | future[["result"]] 24 | } 25 | -------------------------------------------------------------------------------- /R/infix_api-01-futureAssign_OP.R: -------------------------------------------------------------------------------- 1 | #' @usage x \%<-\% value 2 | #' 3 | #' @aliases %<-% %->% 4 | #' @rdname futureAssign 5 | #' 6 | #' @export %<-% %->% 7 | `%<-%` <- function(x, value) { 8 | target <- substitute(x) 9 | expr <- substitute(value) 10 | envir <- parent.frame(1) 11 | futureAssignInternal(target, expr, envir = envir, substitute = FALSE) 12 | } 13 | 14 | `%->%` <- function(value, x) { 15 | target <- substitute(x) 16 | expr <- substitute(value) 17 | envir <- parent.frame(1) 18 | futureAssignInternal(target, expr, envir = envir, substitute = FALSE) 19 | } 20 | 21 | 22 | #' @importFrom listenv get_variable parse_env_subset 23 | futureAssignInternal <- function(target, expr, envir = parent.frame(), substitute = FALSE) { 24 | target <- parse_env_subset(target, envir = envir, substitute = substitute) 25 | assign.env <- target[["envir"]] 26 | 27 | name <- target[["name"]] 28 | if (inherits(target[["envir"]], "listenv")) { 29 | n <- length(target[["exists"]]) 30 | if (n == 0L) { 31 | stop("Cannot future assign to an empty set") 32 | } else if (n > 1L) { 33 | stop("Cannot future assign to more than one element") 34 | } 35 | if (target[["exists"]]) { 36 | name <- get_variable(target[["envir"]], target[["idx"]], mustExist = TRUE, create = FALSE) 37 | } else { 38 | if (!is.na(name) && nzchar(name)) { 39 | name <- get_variable(target[["envir"]], name, mustExist = FALSE, create = TRUE) 40 | } else if (all(is.finite(target[["idx"]]))) { 41 | name <- get_variable(target[["envir"]], target[["idx"]], mustExist = FALSE, create = TRUE) 42 | } else if (all(is.na(target[["idx"]]))) { 43 | stop("subscript out of bounds") 44 | } else { 45 | stop("INTERNAL ERROR: Zero length variable name and unknown index") 46 | } 47 | } 48 | } 49 | 50 | futureAssign(name, expr, envir = envir, assign.env = assign.env, substitute = FALSE) 51 | } # futureAssignInternal() 52 | -------------------------------------------------------------------------------- /R/infix_api-02-globals_OP.R: -------------------------------------------------------------------------------- 1 | #' Specify globals and packages for a future assignment 2 | #' 3 | #' @usage 4 | #' fassignment \%globals\% globals 5 | #' fassignment \%packages\% packages 6 | #' 7 | #' @inheritParams future 8 | #' 9 | #' @param fassignment The future assignment, e.g. 10 | #' `x %<-% { expr }`. 11 | #' 12 | #' @param packages (optional) a character vector specifying packages 13 | #' to be attached in the \R environment evaluating the future. 14 | #' 15 | #' @aliases %packages% 16 | #' @rdname futureAssign 17 | #' 18 | #' @export 19 | `%globals%` <- function(fassignment, globals) { 20 | fassignment <- substitute(fassignment) 21 | envir <- parent.frame(1) 22 | 23 | ## Temporarily set 'globals' argument 24 | args <- getOption("future.disposable", list()) 25 | args["globals"] <- list(globals) 26 | options(future.disposable = args) 27 | on.exit(options(future.disposable = NULL)) 28 | 29 | eval(fassignment, envir = envir, enclos = baseenv()) 30 | } 31 | 32 | #' @export 33 | `%packages%` <- function(fassignment, packages) { 34 | fassignment <- substitute(fassignment) 35 | envir <- parent.frame(1) 36 | 37 | ## Temporarily set 'packages' argument 38 | args <- getOption("future.disposable", list()) 39 | args["packages"] <- list(packages) 40 | options(future.disposable = args) 41 | on.exit(options(future.disposable = NULL)) 42 | 43 | eval(fassignment, envir = envir, enclos = baseenv()) 44 | } 45 | -------------------------------------------------------------------------------- /R/infix_api-03-seed_OP.R: -------------------------------------------------------------------------------- 1 | #' Set random seed for future assignment 2 | #' 3 | #' @usage fassignment \%seed\% seed 4 | #' 5 | #' @param fassignment The future assignment, e.g. 6 | #' `x %<-% { expr }`. 7 | #' @inheritParams future 8 | #' 9 | #' @aliases %seed% 10 | #' @rdname futureAssign 11 | #' 12 | #' @export 13 | `%seed%` <- function(fassignment, seed) { 14 | fassignment <- substitute(fassignment) 15 | envir <- parent.frame(1) 16 | 17 | ## Temporarily set 'seed' argument 18 | args <- getOption("future.disposable", list()) 19 | args["seed"] <- list(seed) 20 | options(future.disposable = args) 21 | on.exit(options(future.disposable = NULL)) 22 | 23 | eval(fassignment, envir = envir, enclos = baseenv()) 24 | } 25 | -------------------------------------------------------------------------------- /R/infix_api-04-stdout_OP.R: -------------------------------------------------------------------------------- 1 | #' Control whether standard output should be captured or not 2 | #' 3 | #' @usage fassignment \%stdout\% capture 4 | #' 5 | #' @param fassignment The future assignment, e.g. 6 | #' `x %<-% { expr }`. 7 | #' 8 | #' @param capture If TRUE, the standard output will be captured, otherwise not. 9 | #' 10 | #' @aliases %stdout% 11 | #' @rdname futureAssign 12 | #' 13 | #' @export 14 | `%stdout%` <- function(fassignment, capture) { 15 | fassignment <- substitute(fassignment) 16 | envir <- parent.frame(1) 17 | 18 | ## Temporarily set 'lazy' argument 19 | args <- getOption("future.disposable", list()) 20 | args["stdout"] <- list(capture) 21 | options(future.disposable = args) 22 | on.exit(options(future.disposable = NULL)) 23 | 24 | eval(fassignment, envir = envir, enclos = baseenv()) 25 | } 26 | -------------------------------------------------------------------------------- /R/infix_api-05-conditions_OP.R: -------------------------------------------------------------------------------- 1 | #' Control whether standard output should be captured or not 2 | #' 3 | #' @usage fassignment \%conditions\% capture 4 | #' 5 | #' @param fassignment The future assignment, e.g. 6 | #' `x %<-% { expr }`. 7 | #' 8 | #' @param capture If TRUE, the standard output will be captured, otherwise not. 9 | #' 10 | #' @aliases %conditions% 11 | #' @rdname futureAssign 12 | #' @export 13 | `%conditions%` <- function(fassignment, capture) { 14 | fassignment <- substitute(fassignment) 15 | envir <- parent.frame(1) 16 | 17 | ## Temporarily set 'lazy' argument 18 | args <- getOption("future.disposable", list()) 19 | args["conditions"] <- list(capture) 20 | options(future.disposable = args) 21 | on.exit(options(future.disposable = NULL)) 22 | 23 | eval(fassignment, envir = envir, enclos = baseenv()) 24 | } 25 | -------------------------------------------------------------------------------- /R/infix_api-06-lazy_OP.R: -------------------------------------------------------------------------------- 1 | #' Control lazy / eager evaluation for a future assignment 2 | #' 3 | #' @usage fassignment \%lazy\% lazy 4 | #' 5 | #' @param fassignment The future assignment, e.g. 6 | #' `x %<-% { expr }`. 7 | #' @inheritParams future 8 | #' 9 | #' @aliases %lazy% 10 | #' @rdname futureAssign 11 | #' 12 | #' @export 13 | `%lazy%` <- function(fassignment, lazy) { 14 | fassignment <- substitute(fassignment) 15 | envir <- parent.frame(1) 16 | 17 | ## Temporarily set 'lazy' argument 18 | args <- getOption("future.disposable", list()) 19 | args["lazy"] <- list(lazy) 20 | options(future.disposable = args) 21 | on.exit(options(future.disposable = NULL)) 22 | 23 | eval(fassignment, envir = envir, enclos = baseenv()) 24 | } 25 | -------------------------------------------------------------------------------- /R/infix_api-07-label_OP.R: -------------------------------------------------------------------------------- 1 | #' Specify label for a future assignment 2 | #' 3 | #' @usage fassignment \%label\% label 4 | #' 5 | #' @param fassignment The future assignment, e.g. 6 | #' `x %<-% { expr }`. 7 | #' @inheritParams future 8 | #' 9 | #' @aliases %label% 10 | #' @rdname futureAssign 11 | #' 12 | #' @export 13 | `%label%` <- function(fassignment, label) { 14 | fassignment <- substitute(fassignment) 15 | envir <- parent.frame(1) 16 | 17 | ## Temporarily set 'label' argument 18 | args <- getOption("future.disposable", list()) 19 | args["label"] <- list(label) 20 | options(future.disposable = args) 21 | on.exit(options(future.disposable = NULL)) 22 | 23 | eval(fassignment, envir = envir, enclos = baseenv()) 24 | } 25 | -------------------------------------------------------------------------------- /R/infix_api-08-plan_OP.R: -------------------------------------------------------------------------------- 1 | #' Use a specific plan for a future assignment 2 | #' 3 | #' @usage fassignment \%plan\% strategy 4 | #' 5 | #' @param fassignment The future assignment, e.g. 6 | #' `x %<-% { expr }`. 7 | #' @param strategy The backend controlling how the future is 8 | #' resolved. See [plan()] for further details. 9 | #' 10 | #' @aliases %plan% 11 | #' @rdname futureAssign 12 | #' 13 | #' @export 14 | `%plan%` <- function(fassignment, strategy) { 15 | fassignment <- substitute(fassignment) 16 | strategy <- substitute(strategy) 17 | envir <- parent.frame(1) 18 | 19 | ## Temporarily use a different plan 20 | oplan <- plan("list") 21 | on.exit({ 22 | ## Note, we cannot use .cleanup = TRUE here, because the 23 | ## future created with the future assignment, needs it 24 | ## the backend to be alive in order for result() to work. 25 | ## FIXME: Figure out how to delay the cleanup until 26 | ## the delayed future assignment is resolved. /HB 2025-03-11 27 | plan(oplan, substitute = FALSE, .call = NULL, .cleanup = FALSE, .init = FALSE) 28 | }) 29 | plan(strategy, substitute = FALSE, .call = NULL, .cleanup = FALSE, .init = FALSE) 30 | 31 | eval(fassignment, envir = envir, enclos = baseenv()) 32 | } 33 | -------------------------------------------------------------------------------- /R/infix_api-09-tweak_OP.R: -------------------------------------------------------------------------------- 1 | #' Temporarily tweaks the arguments of the current backend 2 | #' 3 | #' @usage fassignment \%tweak\% tweaks 4 | #' 5 | #' @param fassignment The future assignment, e.g. 6 | #' `x %<-% { expr }`. 7 | #' @param tweaks A named list (or vector) with arguments that 8 | #' should be changed relative to the current backend. 9 | #' 10 | #' @aliases %tweak% 11 | #' @rdname futureAssign 12 | #' 13 | #' @export 14 | `%tweak%` <- function(fassignment, tweaks) { 15 | fassignment <- substitute(fassignment) 16 | envir <- parent.frame(1) 17 | stop_if_not(is.vector(tweaks)) 18 | tweaks <- as.list(tweaks) 19 | stop_if_not(!is.null(names(tweaks))) 20 | 21 | ## Temporarily use a different plan 22 | oplan <- plan("list") 23 | on.exit(plan(oplan, substitute = FALSE, .call = NULL, .cleanup = FALSE, .init = FALSE)) 24 | 25 | ## Tweak current strategy and apply 26 | plans <- oplan 27 | strategy <- plans[[1]] 28 | args <- c(list(strategy, penvir = envir), tweaks) 29 | strategy <- do.call(tweak, args = args) 30 | plans[[1]] <- strategy 31 | plan(plans, substitute = FALSE, .call = NULL, .cleanup = FALSE, .init = TRUE) 32 | 33 | eval(fassignment, envir = envir, enclos = baseenv()) 34 | } 35 | -------------------------------------------------------------------------------- /R/protected_api-futures.R: -------------------------------------------------------------------------------- 1 | #' Get all futures in a container 2 | #' 3 | #' Gets all futures in an environment, a list, or a list environment 4 | #' and returns an object of the same class (and dimensions). 5 | #' Non-future elements are returned as is. 6 | #' 7 | #' @param x An environment, a list, or a list environment. 8 | #' @param \ldots Not used. 9 | #' 10 | #' @return An object of same type as `x` and with the same names 11 | #' and/or dimensions, if set. 12 | #' 13 | #' @details 14 | #' This function is useful for retrieve futures that were created via 15 | #' future assignments (`%<-%`) and therefore stored as promises. 16 | #' This function turns such promises into standard `Future` 17 | #' objects. 18 | #' 19 | #' @export 20 | futures <- function(x, ...) UseMethod("futures") 21 | 22 | #' @export 23 | futures.list <- function(x, ...) { 24 | x 25 | } 26 | 27 | #' @export 28 | futures.environment <- function(x, ...) { 29 | fs <- futureOf(envir = x, mustExist = FALSE, drop = FALSE) 30 | 31 | ## Create object of same class as 'x' 32 | res <- new.env() 33 | for (key in names(fs)) { 34 | f <- fs[[key]] 35 | if (inherits(f, "Future")) { 36 | res[[key]] <- f 37 | } else { 38 | res[[key]] <- x[[key]] 39 | } 40 | } 41 | 42 | res 43 | } 44 | 45 | #' @export 46 | #' @importFrom listenv listenv 47 | futures.listenv <- function(x, ...) { 48 | fs <- futureOf(envir = x, mustExist = FALSE, drop = FALSE) 49 | 50 | ## Create object of same class as 'x' 51 | res <- listenv() 52 | length(res) <- length(fs) 53 | for (ii in seq_along(fs)) { 54 | f <- fs[[ii]] 55 | if (inherits(f, "Future")) { 56 | res[[ii]] <- f 57 | } else { 58 | value <- x[[ii]] 59 | if (is.null(value)) { 60 | res[ii] <- list(value) 61 | } else { 62 | res[[ii]] <- value 63 | } 64 | } 65 | } 66 | 67 | dim <- dim(x) 68 | if (!is.null(dim)) { 69 | dim(res) <- dim 70 | ## Preserve dimnames and names 71 | dimnames(res) <- dimnames(x) 72 | } 73 | names(res) <- names(x) 74 | 75 | res 76 | } 77 | -------------------------------------------------------------------------------- /R/testme.R: -------------------------------------------------------------------------------- 1 | ## This runs 'testme' test inst/testme/test-.R scripts 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | testme <- function(name) { 4 | path <- system.file(package = 'future', 'testme', mustWork = TRUE) 5 | Sys.setenv(R_TESTME_PATH = path) 6 | Sys.setenv(R_TESTME_PACKAGE = 'future') 7 | Sys.setenv(R_TESTME_NAME = name) 8 | on.exit(Sys.unsetenv('R_TESTME_NAME')) 9 | source(file.path(path, 'run.R')) 10 | } 11 | -------------------------------------------------------------------------------- /R/utils-conditions.R: -------------------------------------------------------------------------------- 1 | stopf <- function(fmt, ..., call. = TRUE, domain = NULL) { #nolint 2 | msg <- sprintf(fmt, ...) 3 | msg <- .makeMessage(msg, domain = domain) 4 | if (is.call(call.)) { 5 | call <- call. 6 | } else if (isTRUE(call)) { 7 | call <- sys.call(which = -1L) 8 | } else { 9 | call <- NULL 10 | } 11 | cond <- simpleError(msg, call = call) 12 | stop(cond) 13 | } 14 | 15 | warnf <- function(fmt, ..., call. = TRUE, immediate. = FALSE, domain = NULL) { #nolint 16 | msg <- sprintf(fmt, ...) 17 | ## Cannot tweak 'call' when immediate. = TRUE 18 | if (isTRUE(immediate.)) { 19 | warning(msg, call. = call., immediate. = immediate., domain = domain) 20 | } else { 21 | msg <- .makeMessage(msg, domain = domain) 22 | if (is.call(call.)) { 23 | call <- call. 24 | } else if (isTRUE(call)) { 25 | call <- sys.call(which = -1L) 26 | } else { 27 | call <- NULL 28 | } 29 | cond <- simpleWarning(msg, call = call) 30 | warning(cond) 31 | } 32 | } 33 | 34 | msgf <- function(fmt, ..., appendLF = FALSE, domain = NULL) { #nolint 35 | message(sprintf(fmt, ...), appendLF = appendLF, domain = domain) 36 | } 37 | -------------------------------------------------------------------------------- /R/utils-connections.R: -------------------------------------------------------------------------------- 1 | ## This is needed in order to be able to assert that we later 2 | ## actually work with the same connection. See R-devel thread 3 | ## 'closeAllConnections() can really mess things up' on 2016-10-30 4 | ## (https://stat.ethz.ch/pipermail/r-devel/2016-October/073331.html) 5 | #' @importFrom parallelly isConnectionValid 6 | check_connection_details <- function(worker, future) { 7 | con <- worker[["con"]] 8 | 9 | ## Not a worker with a connection? 10 | if (!inherits(con, "connection")) return(NULL) 11 | 12 | isValid <- isConnectionValid(con) 13 | if (isValid) return(NULL) 14 | 15 | label <- sQuoteLabel(future) 16 | 17 | reason <- attr(isValid, "reason", exact = TRUE) 18 | reason <- gsub("[.]?[[:space:]]*$", "", reason) 19 | msg <- sprintf("The socket connection to the worker of %s future (%s) is lost or corrupted: %s", class(future)[1], label, reason) 20 | sprintf("%s. As an example, this may happen if base::closeAllConnections() have been called, for instance via base::sys.save.image() which in turn is called if the R session (pid %s) is forced to terminate", msg, Sys.getpid()) 21 | } 22 | -------------------------------------------------------------------------------- /R/utils-prune_pkg_code.R: -------------------------------------------------------------------------------- 1 | with_assert <- function(expr, ...) { 2 | invisible(expr) 3 | } 4 | 5 | prune_call <- function(expr, name) { 6 | if (!is.call(expr)) 7 | return(expr) 8 | expr <- unclass(expr) 9 | fcn <- expr[[1]] 10 | if (!is.symbol(fcn)) 11 | return(expr) 12 | if (as.character(fcn) != name) 13 | return(expr) 14 | NULL 15 | } 16 | 17 | prune_debug <- function(expr) { 18 | if (!is.call(expr)) 19 | return(expr) 20 | expr <- unclass(expr) 21 | fcn <- expr[[1]] 22 | if (!is.symbol(fcn)) 23 | return(expr) 24 | 25 | ## if (debug) { ... } 26 | if (as.character(fcn) == "if") { 27 | cond <- expr[[2]] 28 | if (!is.symbol(cond)) 29 | return(expr) 30 | if (as.character(cond) != "debug") 31 | return(expr) 32 | expr <- NULL 33 | } else if (as.character(fcn) == "<-") { 34 | lhs <- expr[[2]] 35 | if (!is.symbol(lhs)) 36 | return(expr) 37 | if (as.character(lhs) != "debug") 38 | return(expr) 39 | expr <- quote(debug <- FALSE) 40 | } 41 | expr 42 | } 43 | 44 | prune_fcns <- function(expr) { 45 | expr <- prune_call(expr, name = "stop_if_not") 46 | expr <- prune_call(expr, name = "with_assert") 47 | expr <- prune_call(expr, name = "assert_no_positional_args_but_first") 48 | expr <- prune_call(expr, name = "assertValidConnection") 49 | expr <- prune_debug(expr) 50 | # expr <- prune_call(expr, name = "assertOwner") 51 | expr 52 | } 53 | 54 | prune_fcn <- function(name, envir) { 55 | if (exists(name, mode = "function", envir = envir, inherits = FALSE)) { 56 | fcn <- get(name, mode = "function", envir = envir, inherits = FALSE) 57 | body0 <- body(fcn) 58 | body <- walkAST(body0, call = prune_fcns) 59 | if (!identical(body, body0)) { 60 | attrs <- attributes(fcn) 61 | body(fcn) <- body 62 | attributes(fcn) <- attrs ## attributes are lost if body is changed 63 | assign(name, fcn, envir = envir, inherits = FALSE) 64 | return(TRUE) 65 | } 66 | } 67 | FALSE 68 | } 69 | 70 | #' @importFrom globals walkAST 71 | prune_pkg_code <- function(env = topenv(parent.frame())) { 72 | res <- lapply(names(env), FUN = prune_fcn, envir = env) 73 | env <- environment(plan) 74 | res <- lapply(names(env), FUN = prune_fcn, envir = env) 75 | } 76 | -------------------------------------------------------------------------------- /R/utils-registerClusterTypes.R: -------------------------------------------------------------------------------- 1 | ## Register makeClusterMPI() and makeClusterPSOCK() as a cluster types 2 | ## such that they can be created using parallel::makeCluster(), e.g. 3 | ## cl <- parallel::makeCluster(..., type = parallelly::RPSOCK) 4 | 5 | #' @rawNamespace if (getRversion() >= "4.4") export(FUTURE) 6 | FUTURE <- "future::FUTURE" 7 | 8 | registerClusterTypes <- local({ 9 | done <- FALSE 10 | 11 | function() { 12 | if (done) return() 13 | 14 | ns <- getNamespace("parallel") 15 | ## Only available in R (>= 4.5.0) 16 | if (!exists("registerClusterType", envir = ns)) return() 17 | 18 | registerClusterType <- get("registerClusterType", envir = ns) 19 | 20 | ## WORKAROUND: 'R CMD build' somehow creates and calls this function 21 | ## twice, resulting in warnings from parallel::registerClusterType(). 22 | suppressWarnings({ 23 | registerClusterType(FUTURE, makeClusterFuture, make.default = FALSE) 24 | }) 25 | done <<- TRUE 26 | } 27 | }) 28 | -------------------------------------------------------------------------------- /R/utils-signalEarly.R: -------------------------------------------------------------------------------- 1 | signalEarly <- function(future, collect = TRUE, .signalEarly = TRUE, ...) { 2 | ## Don't signal early? 3 | if (!isTRUE(future[["earlySignal"]])) return(future) 4 | 5 | ## Future is not yet launched 6 | if (future[["state"]] == "created") return(future) 7 | 8 | debug <- isTRUE(getOption("future.debug")) 9 | if (debug) mdebug_push("signalEarly() ...") 10 | 11 | ## Nothing to do? 12 | if (!collect && !resolved(future, .signalEarly = FALSE)) { 13 | if (debug) { 14 | mdebug("Future not resolved and collect = FALSE. Skipping") 15 | mdebug_pop() 16 | } 17 | return(future) 18 | } 19 | 20 | result <- result(future) 21 | stop_if_not(inherits(result, "FutureResult")) 22 | 23 | conditions <- result[["conditions"]] 24 | 25 | ## Nothing to do? 26 | if (!.signalEarly || length(conditions) == 0L) { 27 | if (debug) { 28 | if (!.signalEarly) mdebug("Skipping because .signalEarly = FALSE") 29 | if (length(conditions) == 0L) mdebug("No conditions to signal") 30 | mdebug_pop() 31 | } 32 | return(future) 33 | } 34 | 35 | if (debug) { 36 | conditionClasses <- vapply(conditions, 37 | FUN = function(c) class(c[["condition"]])[1], 38 | FUN.VALUE = NA_character_) 39 | mdebugf("signalEarly(): Condition classes = [n=%s] %s", 40 | length(conditionClasses), hpaste(sQuote(conditionClasses))) 41 | } 42 | 43 | signalConditions(future, resignal = FALSE) 44 | 45 | if (debug) mdebug_pop() 46 | 47 | future 48 | } 49 | -------------------------------------------------------------------------------- /R/utils-stealth_sample.R: -------------------------------------------------------------------------------- 1 | ## A version of base::sample() that does not change .Random.seed 2 | stealth_sample <- function(x, size = length(x), replace = FALSE, ...) { 3 | ## Nothing to do? 4 | if (size == 0L) return(x[integer(0)]) 5 | 6 | ## Nothing to randomize? 7 | if (length(x) == 1L) { 8 | if (!replace && size > 1L) { 9 | stopf("Cannot take a sample (n = %d) larger than the population (m = %d) when 'replace = FALSE'", size, length(x)) 10 | } 11 | return(rep(x, times = size)) 12 | } 13 | 14 | oseed <- .GlobalEnv[[".Random.seed"]] 15 | on.exit({ 16 | if (is.null(oseed)) { 17 | rm(list = ".Random.seed", envir = .GlobalEnv, inherits = FALSE) 18 | } else { 19 | .GlobalEnv[[".Random.seed"]] <- oseed 20 | } 21 | }) 22 | 23 | ## Generate a psuedo-random random seed based on the current random 24 | ## state, current time, and the process ID 25 | time_offset <- format(Sys.time(), format = "%H%M%OS6") ## current time 26 | time_offset <- sub(".", "", time_offset, fixed = TRUE) 27 | time_offset <- strsplit(time_offset, split = "", fixed = TRUE)[[1]] 28 | time_offset <- sample(time_offset) ## current RNG state 29 | time_offset <- paste(time_offset, collapse = "") 30 | time_offset <- as.numeric(time_offset) 31 | time_offset <- time_offset + Sys.getpid() ## process ID 32 | time_offset <- time_offset %% .Machine[["integer.max"]] 33 | set.seed(time_offset) 34 | 35 | sample(x, size = size, replace = replace, ...) 36 | } 37 | -------------------------------------------------------------------------------- /R/utils-uuid.R: -------------------------------------------------------------------------------- 1 | ## Create a universally unique identifier (UUID) for an R object 2 | #' @importFrom tools md5sum 3 | #' @importFrom digest digest 4 | uuid <- local({ 5 | ## Use tools::md5sum(), if R (>= 4.5.0). Fall back to digest::digest(). 6 | if ("bytes" %in% names(formals(md5sum))) { 7 | md5 <- function(x) md5sum(bytes = serialize(x, connection = NULL)) 8 | } else { 9 | md5 <- function(x) digest(x, skip = 0L) 10 | } 11 | 12 | function(source, keep_source = FALSE) { 13 | uuid <- md5(source) 14 | if (keep_source) attr(uuid, "source") <- source 15 | uuid 16 | } 17 | }) ## uuid() 18 | 19 | ## A universally unique identifier (UUID) for the current 20 | ## R process UUID. Generated only once per process ID 'pid'. 21 | ## The 'pid' may differ when using forked processes. 22 | session_uuid <- local({ 23 | uuids <- list() 24 | 25 | function(pid = Sys.getpid(), attributes = TRUE) { 26 | pidstr <- as.character(pid) 27 | uuid <- uuids[[pidstr]] 28 | if (!is.null(uuid)) { 29 | if (!attributes) attr(uuid, "source") <- NULL 30 | return(uuid) 31 | } 32 | 33 | info <- Sys.info() 34 | host <- Sys.getenv(c("HOST", "HOSTNAME", "COMPUTERNAME")) 35 | host <- host[nzchar(host)] 36 | host <- if (length(host) == 0L) info[["nodename"]] else host[1L] 37 | info <- list( 38 | host = host, 39 | info = info, 40 | pid = pid, 41 | time = Sys.time(), 42 | random = stealth_sample(.Machine[["integer.max"]], size = 1L) 43 | ) 44 | uuid <- uuid(info, keep_source = TRUE) 45 | uuids[[pidstr]] <<- uuid 46 | if (!attributes) attr(uuid, "source") <- NULL 47 | uuid 48 | } 49 | }) 50 | 51 | future_uuid <- function(owner, counter) { 52 | c(owner, counter) 53 | } 54 | -------------------------------------------------------------------------------- /R/utils-whichIndex.R: -------------------------------------------------------------------------------- 1 | whichIndex <- function(I, dim, dimnames = NULL) { 2 | ndim <- length(dim) 3 | stop_if_not((is.matrix(I) || is.data.frame(I)), ncol(I) == ndim) 4 | if (!is.null(dimnames)) stop_if_not(length(dimnames) == ndim) 5 | if (ndim == 0L) return(integer(0L)) 6 | 7 | if (is.data.frame(I)) { 8 | ## Convert each column to indices 9 | I2 <- array(NA_integer_, dim = dim(I)) 10 | for (kk in 1:ndim) { 11 | idxs <- I[[kk]] 12 | if (is.numeric(idxs)) { 13 | if (any(idxs < 1 | idxs > dim[kk])) { 14 | stop("Index out of range") 15 | } 16 | } else { 17 | idxs <- as.character(idxs) 18 | idxs <- match(idxs, dimnames[[kk]]) 19 | if (anyNA(idxs)) { 20 | unknown <- I[is.na(idxs), kk] 21 | stopf("Unknown indices: %s", hpaste(sQuote(unknown))) 22 | } 23 | } 24 | I2[, kk] <- idxs 25 | } 26 | I <- I2 27 | I2 <- NULL 28 | } else if (is.numeric(I)) { 29 | for (kk in 1:ndim) { 30 | idxs <- I[, kk] 31 | if (any(idxs < 1 | idxs > dim[kk])) { 32 | stop("Index out of range") 33 | } 34 | } 35 | } else { 36 | ## Convert dimnames to dimindices 37 | I2 <- array(NA_integer_, dim = dim(I)) 38 | for (kk in 1:ndim) { 39 | ## Could be, say, factor 40 | idxs <- I[, kk] 41 | idxs <- as.character(idxs) 42 | idxs <- match(idxs, dimnames[[kk]]) 43 | if (anyNA(idxs)) { 44 | unknown <- I[is.na(idxs), kk] 45 | stopf("Unknown indices: %s", hpaste(sQuote(unknown))) 46 | } 47 | I2[, kk] <- idxs 48 | } 49 | I <- I2 50 | I2 <- NULL 51 | } 52 | 53 | ## Nothing more to do? 54 | if (ndim == 1) return(I[, 1L]) 55 | 56 | base <- cumprod(dim[-ndim]) 57 | for (kk in 2:ndim) { 58 | I[, kk] <- (I[, kk] - 1) * base[kk - 1L] 59 | } 60 | rowSums(I) 61 | } 62 | -------------------------------------------------------------------------------- /R/utils_api-backtrace.R: -------------------------------------------------------------------------------- 1 | #' Back trace the expressions evaluated when an error was caught 2 | #' 3 | #' @param future A future with a caught error. 4 | #' 5 | #' @param envir the environment where to locate the future. 6 | #' 7 | #' @param \ldots Not used. 8 | #' 9 | #' @return A list with the future's call stack that led up to the error. 10 | #' 11 | #' @examples 12 | #' my_log <- function(x) log(x) 13 | #' foo <- function(...) my_log(...) 14 | #' 15 | #' f <- future({ foo("a") }) 16 | #' res <- tryCatch({ 17 | #' v <- value(f) 18 | #' }, error = function(ex) { 19 | #' t <- backtrace(f) 20 | #' print(t) 21 | #' }) 22 | #' \dontshow{ 23 | #' ## R CMD check: make sure any open connections are closed afterward 24 | #' plan(sequential) 25 | #' } 26 | #' 27 | #' @export 28 | backtrace <- function(future, envir = parent.frame(), ...) { 29 | ## Argument 'expr': 30 | expr <- substitute(future) 31 | 32 | if (!is.null(expr)) { 33 | future <- tryCatch({ 34 | target <- parse_env_subset(expr, envir = envir, substitute = FALSE) 35 | get_future(target, mustExist = TRUE) 36 | }, error = function(ex) { 37 | eval(expr, envir = envir, enclos = baseenv()) 38 | }) 39 | stop_if_not(inherits(future, "Future")) 40 | } 41 | 42 | if (!resolved(future)) { 43 | stopf("No error has been caught because the future is unresolved: %s", sQuote(expr)) 44 | } 45 | 46 | result <- result(future) 47 | conditions <- result[["conditions"]] 48 | 49 | ## Find 'error' condition 50 | error <- NULL 51 | for (kk in seq_along(conditions)) { 52 | c <- conditions[[kk]] 53 | if (inherits(c[["condition"]], "error")) { 54 | error <- c 55 | break 56 | } 57 | } 58 | 59 | if (is.null(error)) { 60 | stopf("No error was caught for this future: %s", sQuote(expr)) 61 | } 62 | 63 | calls <- error[["calls"]] 64 | 65 | if (is.null(calls)) { 66 | stopf("The error call stack was not recorded for this future: %s", sQuote(expr)) 67 | } 68 | 69 | ## Recreate the full call stack 70 | calls <- c(future[["calls"]], calls) 71 | 72 | calls 73 | } ## backtrace() 74 | -------------------------------------------------------------------------------- /R/utils_api-capture_journals.R: -------------------------------------------------------------------------------- 1 | #' Evaluate an R expression while collecting journals from completed futures 2 | #' 3 | #' @param expr The R expression to evaluate 4 | #' 5 | #' @param substitute If TRUE, then `expr` is subtituted, otherwise not. 6 | #' 7 | #' @param envir The environment where `expr` should be evaluated 8 | #' 9 | #' @details 10 | #' This function evaluates an R expression and capture the journals 11 | #' signaled by futures as they are completed. A future [journal] comprise 12 | #' a log of events appearing during the life-span of a future, e.g. 13 | #' the timestamps when the future was created, launched, queried, 14 | #' resolved, and its results are collected. 15 | #' 16 | #' @return 17 | #' A list of \link[=journal]{FutureJournal}:s. 18 | #' 19 | #' @example incl/capture_journals.R 20 | #' 21 | #' @keywords internal 22 | #' @noRd 23 | capture_journals <- function(expr, substitute = TRUE, envir = parent.frame()) { 24 | oopts <- options(future.journal = TRUE) 25 | on.exit(options(oopts)) 26 | 27 | journals <- NULL 28 | withCallingHandlers({ 29 | eval(expr, envir = envir) 30 | }, FutureJournalCondition = function(cond) { 31 | journals <<- c(journals, list(cond[["journal"]])) 32 | }) 33 | 34 | journals 35 | } 36 | -------------------------------------------------------------------------------- /R/utils_api-minifuture.R: -------------------------------------------------------------------------------- 1 | #' @return 2 | #' `minifuture(expr)` creates a future with minimal overhead, by disabling 3 | #' user-friendly behaviors, e.g. automatic identification of global 4 | #' variables and packages needed, and relaying of output. Unless you have 5 | #' good reasons for using this function, please use [future()] instead. 6 | #' This function exists mainly for the purpose of profiling and identifying 7 | #' which automatic features of [future()] introduce extra overhead. 8 | #' 9 | #' @rdname future 10 | #' @export 11 | minifuture <- function(expr, substitute = TRUE, globals = NULL, packages = NULL, stdout = NA, conditions = NULL, seed = NULL, ..., envir = parent.frame()) { 12 | if (substitute) expr <- substitute(expr) 13 | reset <- character(0L) 14 | future(expr, substitute = FALSE, globals = globals, packages = packages, stdout = stdout, conditions = conditions, seed = seed, reset = reset, ..., envir = envir) 15 | } 16 | -------------------------------------------------------------------------------- /R/utils_api-plan-with.R: -------------------------------------------------------------------------------- 1 | #' Evaluate an expression using a temporarily set future plan 2 | #' 3 | #' @inheritParams plan 4 | #' 5 | #' @param data The future plan to use temporarily. 6 | #' 7 | #' @param expr The R expression to be evaluated. 8 | #' 9 | #' @param \ldots Not used. 10 | #' 11 | #' @param local If TRUE, then the future plan specified by `data` 12 | #' is applied temporarily in the calling frame. Argument `expr` must 13 | #' not be specified if `local = TRUE`. 14 | #' 15 | #' @param envir The environment where the future plan should be set and the 16 | #' expression evaluated. 17 | #' 18 | #' @return The value of the expression evaluated (invisibly). 19 | #' 20 | #' @example incl/with.R 21 | #' 22 | #' @rdname plan 23 | #' @export 24 | with.FutureStrategyList <- function(data, expr, ..., local = FALSE, envir = parent.frame(), .cleanup = NA) { 25 | ## At this point, 'data' has already been resolved by 26 | ## R's dispatching mechanism. At this point, it is 27 | ## too late to override with .cleanup = FALSE. 28 | 29 | temporary <- attr(plan("next"), "with-temporary") 30 | if (is.logical(temporary)) { 31 | old_plan <- data 32 | if (is.na(.cleanup)) .cleanup <- TRUE 33 | } else { 34 | old_plan <- plan(data, .init = FALSE, .cleanup = FALSE) 35 | if (is.na(.cleanup)) .cleanup <- FALSE 36 | } 37 | 38 | if (local) { 39 | if (!missing(expr)) stop("Argument 'expr' must not be specified when local = TRUE") 40 | undoPlan <- function() plan(old_plan, .init = FALSE, .cleanup = .cleanup) 41 | call <- as.call(list(undoPlan)) 42 | args <- list(call, add = TRUE, after = TRUE) 43 | do.call(base::on.exit, args = args, envir = envir) 44 | } else { 45 | on.exit({ 46 | ## Always cleanup the temporarily used backend 47 | plan(old_plan, .init = FALSE, .cleanup = .cleanup) 48 | }) 49 | 50 | invisible(eval(expr, envir = envir)) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | # CRAN submission future 1.49.0 2 | 3 | on 2025-05-08 4 | 5 | I've verified this submission has no negative impact on any of the 433 reverse package dependencies available on CRAN (n = 410) and Bioconductor (n = 23). 6 | 7 | Thank you 8 | 9 | -------------------------------------------------------------------------------- /demo/00Index: -------------------------------------------------------------------------------- 1 | fibonacci Lazy definition of the first 100 Fibonacci numbers 2 | mandelbrot Mandelbrot set images using futures 3 | 4 | 5 | -------------------------------------------------------------------------------- /demo/fibonacci.R: -------------------------------------------------------------------------------- 1 | library(future) 2 | library(listenv) 3 | 4 | ## IMPORTANT: 5 | ## 1. The below usage of lazy futures will only work when they are 6 | ## all evaluated in the same process. 7 | ## 2. We disable the capturing of standard output (stdout=NA) to avoid 8 | ## 'sink stack is full' errors 9 | ## 3. We disable the capturing of most conditions (condition="error") to 10 | ## avoid stacking up too many conditions 11 | oplan <- plan(sequential) 12 | 13 | ## Defines the first 100 Fibonacci numbers 14 | ## (0, 1, 1, 2, 3, 5, 8, ...) 15 | ## but calculate only the ones need when 16 | ## a number is actually requested. 17 | 18 | x <- listenv() 19 | x[[1]] <- 0 20 | x[[2]] <- 1 21 | for (i in 3:100) { 22 | x[[i]] %<-% { x[[i - 2]] + x[[i - 1]] } %lazy% TRUE %stdout% NA %conditions% "error" 23 | } 24 | 25 | ## At this point nothing has been calculated, 26 | ## because lazy evaluation is in place. 27 | 28 | ## Get the 7:th Fibonnaci numbers (should be 8) 29 | print(x[[7]]) 30 | 31 | ## At this point x[1:7] have been calculated, 32 | ## but nothing beyond. 33 | 34 | ## Let's get the 50:th number. 35 | print(x[[50]]) 36 | 37 | ## Reset plan 38 | plan(oplan) 39 | -------------------------------------------------------------------------------- /incl/OVERVIEW.md: -------------------------------------------------------------------------------- 1 | ## TL;DR 2 | 3 | The Futureverse makes it easy to parallelize existing R code - often 4 | with only a minor change of code. It lowers the barriers so that 5 | anyone can safely speed up their existing R code in a worry-free 6 | manner. It is a cross-platform solution that requires no additional 7 | setups or technical skills. Anyone can be up and running within a few 8 | minutes. 9 | 10 | ```r 11 | library(future) 12 | plan(multisession) 13 | 14 | ## Evaluate an R expression sequentially 15 | y <- slow_fcn(X[1]) 16 | 17 | ## Evaluate it in parallel in the background 18 | f <- future(slow_fcn(X[1])) 19 | y <- value(f) 20 | 21 | ## future.apply: futurized version of base R apply 22 | library(future.apply) 23 | y <- lapply(X, slow_fcn) 24 | y <- future_lapply(X, slow_fcn) 25 | 26 | ## furrr: futurized version of purrr 27 | library(furrr) 28 | y <- X |> map(slow_fcn) 29 | y <- X |> future_map(slow_fcn) 30 | 31 | ## foreach: futurized version (modern) 32 | library(foreach) 33 | y <- foreach(x = X) %do% slow_fcn(x) 34 | y <- foreach(x = X) %dofuture% slow_fcn(x) 35 | 36 | ## foreach: futurized version (traditional) 37 | library(foreach) 38 | doFuture::registerDoFuture() 39 | y <- foreach(x = X) %do% slow_fcn(x) 40 | y <- foreach(x = X) %dopar% slow_fcn(x) 41 | ``` 42 | 43 | 44 | <% 45 | ## Reuse the future vignette 46 | md <- R.rsp::rstring(file="vignettes/future-1-overview.md.rsp", postprocess=FALSE) 47 | 48 | ## Drop the header, i.e. anything before the first "H2" header 49 | md <- unlist(strsplit(md, split="\n", fixed=TRUE)) 50 | row <- grep("^## ", md)[1] 51 | if (!is.na(row)) md <- md[-seq_len(row-1)] 52 | 53 | ## Drop the footer, i.e. anything after the first horizontal line 54 | row <- grep("^---", md)[1] 55 | if (!is.na(row)) md <- md[seq_len(row-1)] 56 | 57 | ## Turn otherwise local links to CRAN for README.md 58 | md <- gsub(": (future-.*[.]html)", 59 | ": https://cran.r-project.org/web/packages/future/vignettes/\\1", md) 60 | 61 | ## Output 62 | cat(md, sep="\n") 63 | %> 64 | -------------------------------------------------------------------------------- /incl/as_lecyer_cmrg_seed.R: -------------------------------------------------------------------------------- 1 | # The current RNG kind 2 | okind <- RNGkind() 3 | oseed <- globalenv()$.Random.seed 4 | 5 | # (a) A L'Ecuyer-CMRG seed based on a numeric-scalar seed 6 | seed1 <- future:::as_lecyer_cmrg_seed(42) 7 | str(seed1) 8 | ## int [1:7] 10407 -2133391687 507561766 1260545903 1362917092 -1772566379 -1344458670 9 | # The RNG kind and the RNG state is preserved 10 | stopifnot( 11 | future:::is_lecyer_cmrg_seed(seed1), 12 | identical(RNGkind(), okind), 13 | identical(globalenv()$.Random.seed, oseed) 14 | ) 15 | 16 | # (b) A L'Ecuyer-CMRG seed based on a L'Ecuyer-CMRG seed 17 | seed2 <- future:::as_lecyer_cmrg_seed(seed1) 18 | str(seed2) 19 | ## int [1:7] 10407 -2133391687 507561766 1260545903 1362917092 -1772566379 -1344458670 20 | # The input L'Ecuyer-CMRG seed is returned as-is 21 | stopifnot(identical(seed2, seed1)) 22 | # The RNG kind and the RNG state is preserved 23 | stopifnot( 24 | future:::is_lecyer_cmrg_seed(seed2), 25 | identical(RNGkind(), okind), 26 | identical(globalenv()$.Random.seed, oseed) 27 | ) 28 | 29 | # (c) A L'Ecuyer-CMRG seed based on the current RNG state 30 | seed3 <- future:::as_lecyer_cmrg_seed(TRUE) 31 | str(seed3) 32 | ## int [1:7] 10407 495333909 -1491719214 416071979 49340016 1956499377 899435966 33 | stopifnot(future:::is_lecyer_cmrg_seed(seed3)) 34 | 35 | 36 | # All of the above calls preserve the RNG state including the RNG kind 37 | stopifnot( 38 | identical(RNGkind(), okind), 39 | identical(globalenv()$.Random.seed, oseed) 40 | ) 41 | -------------------------------------------------------------------------------- /incl/capture_journals.R: -------------------------------------------------------------------------------- 1 | slow_fcn <- function(x) { 2 | Sys.sleep(x / 10) 3 | sqrt(x) 4 | } 5 | 6 | plan(multisession, workers = 2) 7 | js <- capture_journals({ 8 | fs <- lapply(3:1, FUN = function(x) future(slow_fcn(x))) 9 | value(fs) 10 | }) 11 | 12 | ## Summarize all journals 13 | js_all <- Reduce(rbind, js) 14 | print(summary(js_all), digits = 2L) 15 | 16 | ## Shut down parallel workers 17 | plan(sequential) 18 | -------------------------------------------------------------------------------- /incl/cluster.R: -------------------------------------------------------------------------------- 1 | \donttest{ 2 | 3 | ## Use cluster futures 4 | cl <- parallel::makeCluster(2, timeout = 60) 5 | plan(cluster, workers = cl) 6 | 7 | ## A global variable 8 | a <- 0 9 | 10 | ## Create future (explicitly) 11 | f <- future({ 12 | b <- 3 13 | c <- 2 14 | a * b * c 15 | }) 16 | 17 | ## A cluster future is evaluated in a separate process. 18 | ## Regardless, changing the value of a global variable will 19 | ## not affect the result of the future. 20 | a <- 7 21 | print(a) 22 | 23 | v <- value(f) 24 | print(v) 25 | stopifnot(v == 0) 26 | 27 | ## CLEANUP 28 | parallel::stopCluster(cl) 29 | 30 | } 31 | -------------------------------------------------------------------------------- /incl/future.R: -------------------------------------------------------------------------------- 1 | ## Evaluate futures in parallel 2 | plan(multisession) 3 | 4 | ## Data 5 | x <- rnorm(100) 6 | y <- 2 * x + 0.2 + rnorm(100) 7 | w <- 1 + x ^ 2 8 | 9 | 10 | ## EXAMPLE: Regular assignments (evaluated sequentially) 11 | fitA <- lm(y ~ x, weights = w) ## with offset 12 | fitB <- lm(y ~ x - 1, weights = w) ## without offset 13 | fitC <- { 14 | w <- 1 + abs(x) ## Different weights 15 | lm(y ~ x, weights = w) 16 | } 17 | print(fitA) 18 | print(fitB) 19 | print(fitC) 20 | 21 | 22 | ## EXAMPLE: Future assignments (evaluated in parallel) 23 | fitA %<-% lm(y ~ x, weights = w) ## with offset 24 | fitB %<-% lm(y ~ x - 1, weights = w) ## without offset 25 | fitC %<-% { 26 | w <- 1 + abs(x) 27 | lm(y ~ x, weights = w) 28 | } 29 | print(fitA) 30 | print(fitB) 31 | print(fitC) 32 | 33 | 34 | ## EXAMPLE: Explicitly create futures (evaluated in parallel) 35 | ## and retrieve their values 36 | fA <- future( lm(y ~ x, weights = w) ) 37 | fB <- future( lm(y ~ x - 1, weights = w) ) 38 | fC <- future({ 39 | w <- 1 + abs(x) 40 | lm(y ~ x, weights = w) 41 | }) 42 | fitA <- value(fA) 43 | fitB <- value(fB) 44 | fitC <- value(fC) 45 | print(fitA) 46 | print(fitB) 47 | print(fitC) 48 | 49 | \dontshow{ 50 | ## Make sure to "close" an multisession workers on Windows 51 | plan(sequential) 52 | } 53 | -------------------------------------------------------------------------------- /incl/futureCall.R: -------------------------------------------------------------------------------- 1 | ## EXAMPLE: futureCall() and do.call() 2 | x <- 1:100 3 | y0 <- do.call(sum, args = list(x)) 4 | print(y0) 5 | 6 | f1 <- futureCall(sum, args = list(x)) 7 | y1 <- value(f1) 8 | print(y1) 9 | -------------------------------------------------------------------------------- /incl/futureOf.R: -------------------------------------------------------------------------------- 1 | a %<-% { 1 } 2 | 3 | f <- futureOf(a) 4 | print(f) 5 | 6 | b %<-% { 2 } 7 | 8 | f <- futureOf(b) 9 | print(f) 10 | 11 | ## All futures 12 | fs <- futureOf() 13 | print(fs) 14 | 15 | 16 | ## Futures part of environment 17 | env <- new.env() 18 | env$c %<-% { 3 } 19 | 20 | f <- futureOf(env$c) 21 | print(f) 22 | 23 | f2 <- futureOf(c, envir = env) 24 | print(f2) 25 | 26 | f3 <- futureOf("c", envir = env) 27 | print(f3) 28 | 29 | fs <- futureOf(envir = env) 30 | print(fs) 31 | -------------------------------------------------------------------------------- /incl/futureSessionInfo.R: -------------------------------------------------------------------------------- 1 | plan(multisession, workers = 2) 2 | futureSessionInfo() 3 | plan(sequential) -------------------------------------------------------------------------------- /incl/journal.R: -------------------------------------------------------------------------------- 1 | ## Enable journaling of futures 2 | oopts <- options(future.journal = TRUE) 3 | 4 | plan(multisession, workers = 2L) 5 | 6 | t_start <- Sys.time() 7 | fs <- lapply(1:3, FUN = function(x) future({ Sys.sleep(x); sqrt(x) })) 8 | vs <- value(fs) 9 | js <- lapply(fs, FUN = journal, baseline = t_start) 10 | print(js) 11 | 12 | ## Stop parallel workers and disable journal logging and signaling 13 | plan(sequential) 14 | options(oopts) 15 | -------------------------------------------------------------------------------- /incl/mandelbrot.R: -------------------------------------------------------------------------------- 1 | counts <- mandelbrot(x = -0.75, y = 0, side = 3) 2 | plot(counts) 3 | 4 | \dontrun{ 5 | demo("mandelbrot", package = "future", ask = FALSE) 6 | } 7 | -------------------------------------------------------------------------------- /incl/multicore.R: -------------------------------------------------------------------------------- 1 | ## Use multicore futures 2 | plan(multicore) 3 | 4 | ## A global variable 5 | a <- 0 6 | 7 | ## Create future (explicitly) 8 | f <- future({ 9 | b <- 3 10 | c <- 2 11 | a * b * c 12 | }) 13 | 14 | ## A multicore future is evaluated in a separate forked 15 | ## process. Changing the value of a global variable 16 | ## will not affect the result of the future. 17 | a <- 7 18 | print(a) 19 | 20 | v <- value(f) 21 | print(v) 22 | stopifnot(v == 0) 23 | -------------------------------------------------------------------------------- /incl/multisession.R: -------------------------------------------------------------------------------- 1 | \donttest{ 2 | 3 | ## Use multisession futures 4 | plan(multisession) 5 | 6 | ## A global variable 7 | a <- 0 8 | 9 | ## Create future (explicitly) 10 | f <- future({ 11 | b <- 3 12 | c <- 2 13 | a * b * c 14 | }) 15 | 16 | ## A multisession future is evaluated in a separate R session. 17 | ## Changing the value of a global variable will not affect 18 | ## the result of the future. 19 | a <- 7 20 | print(a) 21 | 22 | v <- value(f) 23 | print(v) 24 | stopifnot(v == 0) 25 | 26 | ## Explicitly close multisession workers by switching plan 27 | plan(sequential) 28 | } 29 | -------------------------------------------------------------------------------- /incl/nbrOfWorkers.R: -------------------------------------------------------------------------------- 1 | plan(multisession) 2 | nbrOfWorkers() ## == availableCores() 3 | 4 | plan(sequential) 5 | nbrOfWorkers() ## == 1 6 | -------------------------------------------------------------------------------- /incl/plan.R: -------------------------------------------------------------------------------- 1 | a <- b <- c <- NA_real_ 2 | 3 | # An sequential future 4 | plan(sequential) 5 | f <- future({ 6 | a <- 7 7 | b <- 3 8 | c <- 2 9 | a * b * c 10 | }) 11 | y <- value(f) 12 | print(y) 13 | str(list(a = a, b = b, c = c)) ## All NAs 14 | 15 | 16 | # A sequential future with lazy evaluation 17 | plan(sequential) 18 | f <- future({ 19 | a <- 7 20 | b <- 3 21 | c <- 2 22 | a * b * c 23 | }, lazy = TRUE) 24 | y <- value(f) 25 | print(y) 26 | str(list(a = a, b = b, c = c)) ## All NAs 27 | 28 | 29 | # A multicore future (specified as a string) 30 | plan("multicore") 31 | f <- future({ 32 | a <- 7 33 | b <- 3 34 | c <- 2 35 | a * b * c 36 | }) 37 | y <- value(f) 38 | print(y) 39 | str(list(a = a, b = b, c = c)) ## All NAs 40 | 41 | ## Multisession futures gives an error on R CMD check on 42 | ## Windows (but not Linux or macOS) for unknown reasons. 43 | ## The same code works in package tests. 44 | \donttest{ 45 | 46 | # A multisession future (specified via a string variable) 47 | plan("future::multisession") 48 | f <- future({ 49 | a <- 7 50 | b <- 3 51 | c <- 2 52 | a * b * c 53 | }) 54 | y <- value(f) 55 | print(y) 56 | str(list(a = a, b = b, c = c)) ## All NAs 57 | 58 | } 59 | 60 | 61 | ## Explicitly specifying number of workers 62 | ## (default is parallelly::availableCores()) 63 | plan(multicore, workers = 2) 64 | message("Number of parallel workers: ", nbrOfWorkers()) 65 | 66 | 67 | ## Explicitly close multisession workers by switching plan 68 | plan(sequential) 69 | -------------------------------------------------------------------------------- /incl/reset.R: -------------------------------------------------------------------------------- 1 | ## Like mean(), but fails 90% of the time 2 | shaky_mean <- function(x) { 3 | if (as.double(Sys.time()) %% 1 < 0.90) stop("boom") 4 | mean(x) 5 | } 6 | 7 | x <- rnorm(100) 8 | 9 | ## Calculate the mean of 'x' with a risk of failing randomly 10 | f <- future({ shaky_mean(x) }) 11 | 12 | ## Relaunch until success 13 | repeat({ 14 | v <- tryCatch(value(f), error = identity) 15 | if (!inherits(v, "error")) break 16 | message("Resetting failed future, and retry in 0.1 seconds") 17 | f <- reset(f) 18 | Sys.sleep(0.1) 19 | }) 20 | cat("mean:", v, "\n") 21 | -------------------------------------------------------------------------------- /incl/sequential.R: -------------------------------------------------------------------------------- 1 | ## Use sequential futures 2 | plan(sequential) 3 | 4 | ## A global variable 5 | a <- 0 6 | 7 | ## Create a sequential future 8 | f <- future({ 9 | b <- 3 10 | c <- 2 11 | a * b * c 12 | }) 13 | 14 | ## Since 'a' is a global variable in future 'f' which 15 | ## is eagerly resolved (default), this global has already 16 | ## been resolved / incorporated, and any changes to 'a' 17 | ## at this point will _not_ affect the value of 'f'. 18 | a <- 7 19 | print(a) 20 | 21 | v <- value(f) 22 | print(v) 23 | stopifnot(v == 0) 24 | -------------------------------------------------------------------------------- /incl/value.R: -------------------------------------------------------------------------------- 1 | ## ------------------------------------------------------ 2 | ## A single future 3 | ## ------------------------------------------------------ 4 | x <- sample(100, size = 50) 5 | f <- future(mean(x)) 6 | v <- value(f) 7 | message("The average of 50 random numbers in [1,100] is: ", v) 8 | 9 | 10 | 11 | ## ------------------------------------------------------ 12 | ## Ten futures 13 | ## ------------------------------------------------------ 14 | xs <- replicate(10, { list(sample(100, size = 50)) }) 15 | fs <- lapply(xs, function(x) { future(mean(x)) }) 16 | 17 | ## The 10 values as a list (because 'fs' is a list) 18 | vs <- value(fs) 19 | message("The ten averages are:") 20 | str(vs) 21 | 22 | ## The 10 values as a vector (by manually unlisting) 23 | vs <- value(fs) 24 | vs <- unlist(vs) 25 | message("The ten averages are: ", paste(vs, collapse = ", ")) 26 | 27 | ## The values as a vector (by reducing) 28 | vs <- value(fs, reduce = `c`) 29 | message("The ten averages are: ", paste(vs, collapse = ", ")) 30 | 31 | ## Calculate the sum of the averages (by reducing) 32 | total <- value(fs, reduce = `sum`) 33 | message("The sum of the ten averages is: ", total) 34 | -------------------------------------------------------------------------------- /incl/with.R: -------------------------------------------------------------------------------- 1 | # Evaluate a future using the 'multisession' plan 2 | with(plan(multisession, workers = 2), { 3 | f <- future(Sys.getpid()) 4 | w_pid <- value(f) 5 | }) 6 | print(c(main = Sys.getpid(), worker = w_pid)) 7 | 8 | 9 | 10 | # Evaluate a future locally using the 'multisession' plan 11 | local({ 12 | with(plan(multisession, workers = 2), local = TRUE) 13 | 14 | f <- future(Sys.getpid()) 15 | w_pid <- value(f) 16 | print(c(main = Sys.getpid(), worker = w_pid)) 17 | }) 18 | 19 | 20 | -------------------------------------------------------------------------------- /inst/CITATION: -------------------------------------------------------------------------------- 1 | utils::bibentry( 2 | header = "Please cite 'future' and the future framework using the following references:", 3 | 4 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5 | # BibTeX entry: 6 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 7 | bibtype = "article", 8 | key = "RJ-2021-048", 9 | author = "Henrik Bengtsson", 10 | title = "A Unifying Framework for Parallel and Distributed Processing in R using Futures", 11 | year = "2021", 12 | journal = "The R Journal", 13 | doi = "10.32614/RJ-2021-048", 14 | url = "https://doi.org/10.32614/RJ-2021-048", 15 | pages = "208--227", 16 | volume = "13", 17 | number = "2", 18 | 19 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 20 | # Plain-text citation: 21 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 22 | textVersion = paste0( 23 | "Henrik Bengtsson, ", 24 | "A Unifying Framework for Parallel and Distributed Processing in R using Futures, ", 25 | "The R Journal (2021) 13:2, pages 208-227, ", 26 | "doi:10.32614/RJ-2021-048" 27 | ) 28 | ) 29 | -------------------------------------------------------------------------------- /inst/testme/_epilogue/001.undo-future.R: -------------------------------------------------------------------------------- 1 | ## Undo future debug 2 | options(future.debug = FALSE) 3 | 4 | ## Undo future strategy 5 | future::plan(oplan) 6 | -------------------------------------------------------------------------------- /inst/testme/_epilogue/090.gc.R: -------------------------------------------------------------------------------- 1 | ## Travis CI specific: Explicit garbage collection because it 2 | ## looks like Travis CI might run out of memory during 'covr' 3 | ## testing and we now have so many tests. /HB 2017-01-11 4 | if ("covr" %in% loadedNamespaces()) { 5 | res <- gc() 6 | testme <- as.environment("testme") 7 | if (testme[["debug"]]) print(res) 8 | } 9 | -------------------------------------------------------------------------------- /inst/testme/_epilogue/099.session_info.R: -------------------------------------------------------------------------------- 1 | testme <- as.environment("testme") 2 | if (testme[["debug"]]) { 3 | info <- utils::sessionInfo() 4 | message("Session information:") 5 | print(info) 6 | } 7 | -------------------------------------------------------------------------------- /inst/testme/_epilogue/995.detritus-connections.R: -------------------------------------------------------------------------------- 1 | ## Look for detritus files 2 | testme <- as.environment("testme") 3 | local({ 4 | delta <- diff_connections(get_connections(), testme[["testme_connections"]]) 5 | if (any(lengths(delta) > 0)) { 6 | message(sprintf("Detritus connections generated by test %s:", sQuote(testme[["name"]]))) 7 | print(delta) 8 | 9 | ## Close added connections, because they are expected? 10 | if (!is.null(delta[["added"]]) && 11 | "detritus-connections" %in% testme[["tags"]]) { 12 | idxs <- delta[["added"]][["index"]] 13 | for (idx in idxs) { 14 | tryCatch({ 15 | con <- getConnection(idx) 16 | close(con) 17 | }, error = identity) 18 | } 19 | delta <- diff_connections(get_connections(), testme[["testme_connections"]]) 20 | if (any(lengths(delta) > 0)) { 21 | message(sprintf("Detritus connections generated by test %s remains after shutting down expected connections added:", sQuote(testme[["name"]]))) 22 | print(delta) 23 | } else { 24 | message(sprintf("No detritus connections remaining from test %s after shutting down expected ones", sQuote(testme[["name"]]))) 25 | } 26 | } 27 | } 28 | }) 29 | 30 | 31 | -------------------------------------------------------------------------------- /inst/testme/_epilogue/999.detritus-files.R: -------------------------------------------------------------------------------- 1 | ## Look for detritus files 2 | testme <- as.environment("testme") 3 | 4 | local({ 5 | path <- dirname(tempdir()) 6 | 7 | if (basename(path) == "working_dir") { 8 | files <- dir(pattern = "^Rscript", path = path, all.files = TRUE, full.names = TRUE) 9 | if (length(files) > 0L) { 10 | message(sprintf("Detritus 'Rscript*' files generated by test %s:", sQuote(testme[["name"]]))) 11 | print(files) 12 | 13 | ## Remove detritus files produced by this test script, so that 14 | ## other test scripts will not fail because of these files. 15 | unlink(files) 16 | 17 | ## Signal the problem 18 | msg <- sprintf("Detected 'Rscript*' files: [n=%d] %s", length(files), paste(sQuote(basename(files)), collapse = ", ")) 19 | ## Are detritus files files expected by design on MS Windows? 20 | ## If so, produce a warning, otherwise an error 21 | if ("detritus-files" %in% testme[["tags"]] && 22 | .Platform[["OS.type"]] == "windows") { 23 | warning(msg, immediate. = TRUE) 24 | } else { 25 | stop(msg) 26 | } 27 | } 28 | } else { 29 | message(sprintf("Skipping, because path appears not to be an 'R CMD check' folder: %s", sQuote(path))) 30 | } 31 | }) 32 | -------------------------------------------------------------------------------- /inst/testme/_prologue/001.load.R: -------------------------------------------------------------------------------- 1 | loadNamespace("future") 2 | -------------------------------------------------------------------------------- /inst/testme/_prologue/002.record-state.R: -------------------------------------------------------------------------------- 1 | ## Record original state 2 | ovars <- ls(envir = globalenv()) 3 | oenvs <- oenvs0 <- Sys.getenv() 4 | oopts0 <- options() 5 | -------------------------------------------------------------------------------- /inst/testme/_prologue/030.imports.R: -------------------------------------------------------------------------------- 1 | ## Private future functions 2 | .onLoad <- future:::.onLoad 3 | .onAttach <- future:::.onAttach 4 | asIEC <- future:::asIEC 5 | FutureRegistry <- future:::FutureRegistry 6 | gassign <- future:::gassign 7 | get_future <- future:::get_future 8 | geval <- future:::geval 9 | grmall <- future:::grmall 10 | commaq <- future:::commaq 11 | hpaste <- future:::hpaste 12 | importParallel <- future:::importParallel 13 | mdebug <- future:::mdebug 14 | mdebugf <- future:::mdebugf 15 | parseCmdArgs <- future:::parseCmdArgs 16 | requestCore <- future:::requestCore 17 | requestNode <- future:::requestNode 18 | requirePackages <- future:::requirePackages 19 | tweakExpression <- future:::tweakExpression 20 | whichIndex <- future:::whichIndex 21 | isFALSE <- future:::isFALSE 22 | isNA <- future:::isNA 23 | supports_omp_threads <- future:::supports_omp_threads 24 | 25 | get_random_seed <- future:::get_random_seed 26 | set_random_seed <- future:::set_random_seed 27 | as_lecyer_cmrg_seed <- future:::as_lecyer_cmrg_seed 28 | is_lecyer_cmrg_seed <- future:::is_lecyer_cmrg_seed 29 | -------------------------------------------------------------------------------- /inst/testme/_prologue/050.utils.R: -------------------------------------------------------------------------------- 1 | ## Local functions for test scripts 2 | printf <- function(...) cat(sprintf(...)) 3 | mstr <- function(...) message(paste(capture.output(str(...)), collapse = "\n")) 4 | attachLocally <- function(x, envir = parent.frame()) { 5 | for (name in names(x)) { 6 | assign(name, value = x[[name]], envir = envir) 7 | } 8 | } 9 | 10 | ## WORKAROUND: capture.output() gained argument 'split' in R 3.3.0 11 | if (getRversion() >= "3.3.0") { 12 | capture.output <- utils::capture.output 13 | } else { 14 | capture.output <- function(..., split = FALSE) utils::capture.output(...) 15 | } 16 | 17 | recordConditions <- function(expr, ..., parse = TRUE) { 18 | conditions <- list() 19 | withCallingHandlers(expr, condition = function(c) { 20 | attr(c, "received") <- Sys.time() 21 | conditions[[length(conditions) + 1L]] <<- c 22 | }) 23 | conditions 24 | } 25 | 26 | recordRelay <- function(...) { 27 | stdout <- capture.output(conditions <- recordConditions(...), split = TRUE) 28 | if (length(stdout) > 0) stdout <- paste0(stdout, "\n") 29 | msgs <- sapply(conditions, FUN = conditionMessage) 30 | list(stdout = stdout, msgs = msgs) 31 | } 32 | -------------------------------------------------------------------------------- /inst/testme/_prologue/090.context.R: -------------------------------------------------------------------------------- 1 | fullTest <- (Sys.getenv("_R_CHECK_FULL_") != "") 2 | 3 | covr_testing <- ("covr" %in% loadedNamespaces()) 4 | on_macos <- grepl("^darwin", R.version$os) 5 | on_githubactions <- as.logical(Sys.getenv("GITHUB_ACTIONS", "FALSE")) 6 | -------------------------------------------------------------------------------- /inst/testme/_prologue/090.options.R: -------------------------------------------------------------------------------- 1 | ## Default options 2 | oopts <- options( 3 | warn = 1L, 4 | showNCalls = 500L, 5 | mc.cores = 2L, 6 | future.debug = TRUE, 7 | ## Reset the following during testing in case 8 | ## they are set on the test system 9 | future.availableCores.system = NULL, 10 | future.availableCores.fallback = NULL 11 | ) 12 | -------------------------------------------------------------------------------- /inst/testme/_prologue/091.envvars.R: -------------------------------------------------------------------------------- 1 | ## Comment: The below should be set automatically whenever the future package 2 | ## is loaded and 'R CMD check' runs. The below is added in case R is changed 3 | ## in the future and we fail to detect 'R CMD check'. 4 | Sys.setenv(R_PARALLELLY_MAKENODEPSOCK_CONNECTTIMEOUT = 2 * 60) 5 | Sys.setenv(R_PARALLELLY_MAKENODEPSOCK_TIMEOUT = 2 * 60) 6 | Sys.setenv(R_PARALLELLY_MAKENODEPSOCK_SESSIONINFO_PKGS = TRUE) 7 | Sys.setenv(R_FUTURE_WAIT_INTERVAL = 0.01) ## 0.01s (instead of default 0.2s) 8 | 9 | ## Label PSOCK cluster workers (to help troubleshooting) 10 | test_script <- grep("[.]R$", commandArgs(), value = TRUE)[1] 11 | if (is.na(test_script)) test_script <- "UNKNOWN" 12 | worker_label <- sprintf("future/tests/%s:%s:%s:%s", test_script, Sys.info()[["nodename"]], Sys.info()[["user"]], Sys.getpid()) 13 | Sys.setenv(R_PARALLELLY_MAKENODEPSOCK_RSCRIPT_LABEL = worker_label) 14 | 15 | ## Reset the following during testing in case 16 | ## they are set on the test system 17 | oenvs2 <- Sys.unsetenv(c( 18 | "R_PARALLELLY_AVAILABLECORES_SYSTEM", 19 | "R_PARALLELLY_AVAILABLECORES_FALLBACK", 20 | ## SGE 21 | "NSLOTS", "PE_HOSTFILE", 22 | ## Slurm 23 | "SLURM_CPUS_PER_TASK", 24 | ## TORQUE / PBS 25 | "NCPUS", "PBS_NUM_PPN", "PBS_NODEFILE", "PBS_NP", "PBS_NUM_NODES" 26 | )) 27 | -------------------------------------------------------------------------------- /inst/testme/_prologue/099.future-setup.R: -------------------------------------------------------------------------------- 1 | ## Use sequential futures by default 2 | oplan <- local({ 3 | oopts <- options(future.debug = FALSE) 4 | on.exit(options(oopts)) 5 | future::plan(future::sequential) 6 | }) 7 | 8 | supportedStrategies <- function(cores = NA_integer_, excl = "cluster", ...) { 9 | strategies <- future:::supportedStrategies(...) 10 | strategies <- setdiff(strategies, excl) 11 | 12 | if (!is.na(cores)) { 13 | if (cores == 1L) { 14 | strategies <- setdiff(strategies, c("multicore", "multisession")) 15 | } else if (cores > 1L) { 16 | strategies <- setdiff(strategies, "sequential") 17 | } 18 | } 19 | 20 | strategies 21 | } 22 | 23 | availCores <- min(2L, future::availableCores()) 24 | -------------------------------------------------------------------------------- /inst/testme/_prologue/995.detrius-connections.R: -------------------------------------------------------------------------------- 1 | get_connections <- function() { 2 | cons <- lapply(getAllConnections(), FUN = function(idx) { 3 | tryCatch({ 4 | con <- getConnection(idx) 5 | as.data.frame(c(index = idx, summary(con))) 6 | }, error = function(e) { 7 | NULL 8 | }) 9 | }) 10 | do.call(rbind, cons) 11 | } 12 | 13 | diff_connections <- function(after, before) { 14 | index <- NULL ## To please R CMD check 15 | 16 | ## Nothing to do? 17 | if (length(before) + length(after) == 0L) { 18 | return(c(added = NULL, removed = NULL, replaced = NULL)) 19 | } 20 | 21 | idxs <- setdiff(after[["index"]], before[["index"]]) 22 | if (length(idxs) > 0) { 23 | added <- subset(after, index %in% idxs) 24 | after <- subset(after, ! index %in% idxs) 25 | } else { 26 | added <- NULL 27 | } 28 | 29 | idxs <- setdiff(before[["index"]], after[["index"]]) 30 | if (length(idxs) > 0) { 31 | removed <- subset(before, index %in% idxs) 32 | before <- subset(before, ! index %in% idxs) 33 | } else { 34 | removed <- NULL 35 | } 36 | 37 | idxs <- intersect(before[["index"]], after[["index"]]) 38 | if (length(idxs) > 0) { 39 | replaced <- list() 40 | for (idx in idxs) { 41 | before_idx <- subset(before, index == idx) 42 | after_idx <- subset(after, index == idx) 43 | if (!identical(before_idx, after_idx)) { 44 | for (name in colnames(after_idx)) { 45 | value <- after_idx[[name]] 46 | if (!identical(before_idx[[name]], value)) { 47 | value <- sprintf("%s (was %s)", value, before_idx[[name]]) 48 | after_idx[[name]] <- value 49 | } 50 | } 51 | replaced <- c(replaced, list(after_idx)) 52 | } 53 | } 54 | replaced <- do.call(rbind, replaced) 55 | } else { 56 | replaced <- NULL 57 | } 58 | 59 | list(added = added, removed = removed, replaced = replaced) 60 | } 61 | 62 | testme <- as.environment("testme") 63 | testme[["testme_connections"]] <- get_connections() 64 | -------------------------------------------------------------------------------- /inst/testme/test-000.R: -------------------------------------------------------------------------------- 1 | #' @tags prologue-cleanup 2 | #' @tags detritus-files 3 | 4 | message("Test to clean up any detritus files that might originate from R CMD check running examples") 5 | 6 | -------------------------------------------------------------------------------- /inst/testme/test-FutureError.R: -------------------------------------------------------------------------------- 1 | #' @tags FutureError 2 | #' @tags sequential 3 | 4 | library(future) 5 | 6 | message("*** FutureError class ...") 7 | 8 | ## Minimal 9 | ex <- FutureError(message = "Woops") 10 | print(ex) 11 | 12 | cond <- tryCatch(message("Woops", appendLF = FALSE), message = identity) 13 | ex2 <- FutureError(message = cond) 14 | print(ex2) 15 | stopifnot(conditionMessage(ex2) == conditionMessage(ex)) 16 | 17 | f <- future({ 42L; stop("woops") }) 18 | v <- value(f, signal = FALSE) 19 | print(v) 20 | ex <- FutureError(message = "Woops", future = f) 21 | print(ex) 22 | 23 | message("*** FutureError class ... DONE") 24 | 25 | -------------------------------------------------------------------------------- /inst/testme/test-FutureGlobals.R: -------------------------------------------------------------------------------- 1 | #' @tags FutureGlobals 2 | 3 | library(future) 4 | 5 | message("*** FutureGlobals() ...") 6 | 7 | fg1 <- FutureGlobals() 8 | print(fg1) 9 | 10 | fg2 <- FutureGlobals(fg1) 11 | print(fg2) 12 | 13 | g <- globals::as.Globals(list(a = 1, b = 1:3)) 14 | print(g) 15 | 16 | fg3 <- FutureGlobals(g) 17 | print(fg3) 18 | 19 | fg4 <- as.FutureGlobals(g) 20 | print(fg4) 21 | 22 | print(resolved(fg3)) 23 | 24 | fg <- fg4 25 | 26 | fg_unique <- unique(fg) 27 | print(fg_unique) 28 | 29 | fg_resolved <- resolve(fg) 30 | print(fg_resolved) 31 | 32 | message("- FutureGlobals() - exceptions ...") 33 | 34 | res <- tryCatch(g <- FutureGlobals(NULL), error = identity) 35 | print(res) 36 | stopifnot(inherits(res, "error")) 37 | 38 | message("*** FutureGlobals() ... DONE") 39 | 40 | -------------------------------------------------------------------------------- /inst/testme/test-adhoc_native_to_utf8.R: -------------------------------------------------------------------------------- 1 | #' @tags windows 2 | 3 | library(future) 4 | 5 | adhoc_native_to_utf8 <- future:::adhoc_native_to_utf8 6 | 7 | ## WORKAROUND: In order to avoid this test script itself to use UTF-8 8 | ## encoding, we generate such UTF-8 strings at run-time instead from 9 | ## escaped UTF-8 strings. 10 | strings <- c( 11 | "[x] hello" = "[x] hello", 12 | "\\u2713 hello" = " hello", 13 | "'\\u2713 hello'" = "' hello'", 14 | '"\\u2713 hello"' = '" hello"', 15 | "\\u306B hello" = " hello" 16 | ) 17 | for (kk in seq_along(strings)) { 18 | name <- names(strings)[kk] 19 | code <- paste('"', gsub('"', '\\"', name, fixed = TRUE), '"', sep = "") 20 | name <- eval(parse(text = code)) 21 | names(strings)[kk] <- name 22 | } 23 | 24 | for (kk in seq_along(strings)) { 25 | message(sprintf("Test case #%d:", kk)) 26 | truth <- names(strings)[kk] 27 | input <- strings[[kk]] 28 | output <- adhoc_native_to_utf8(input) 29 | message(sprintf(" - input: %s", input)) 30 | message(sprintf(" - output: %s", output)) 31 | message(sprintf(" - truth: %s", truth)) 32 | ## NOTE: Not all MS Windows environment support UTF-8. Then 33 | ## the above does not work and input == truth 34 | stopifnot(identical(input, truth) || identical(output, truth)) 35 | } 36 | -------------------------------------------------------------------------------- /inst/testme/test-bquote.R: -------------------------------------------------------------------------------- 1 | #' @tags bquote 2 | 3 | library(future) 4 | 5 | bquote_compile <- future:::bquote_compile 6 | bquote_apply <- future:::bquote_apply 7 | 8 | message("*** bquote_compile() & bquote_apply() ...") 9 | 10 | exprs <- list( 11 | A = quote(.(a)), 12 | B = quote(1 + .(a)), 13 | C = quote(.(a) + 2), 14 | D = quote({ .(a) }), 15 | E = quote({ 1 + .(a) }), 16 | F = quote(function(x = 42) { x + .(a) }), 17 | G = quote({ 1 + .(a + 2) * c(1, 2, .(b)) }), 18 | H = quote(.(a + 1)), 19 | I = quote(.(a + 1) + .(a)), 20 | J = quote(function(a=.(a)) NULL) 21 | ) 22 | 23 | 24 | for (kk in seq_along(exprs)) { 25 | name <- names(exprs)[kk] 26 | message(sprintf("Expression #%d (%s) of %d:", 27 | kk, sQuote(name), length(exprs))) 28 | expr <- exprs[[kk]] 29 | print(expr) 30 | 31 | for (a in list(1, quote(A), quote(c()), NULL)) { 32 | for (b in list(1, quote(B), quote(c()), NULL)) { 33 | str(list(a = a, b = b)) 34 | 35 | truth <- tryCatch({ 36 | eval(as.call(list(quote(base::bquote), expr))) 37 | }, error = identity) 38 | if (inherits(truth, "error")) next 39 | 40 | tmpl <- bquote_compile(expr, substitute = FALSE) 41 | expr2 <- bquote_apply(tmpl) 42 | print(expr2) 43 | 44 | if (!isTRUE(all.equal(expr2, truth))) { 45 | str(list(name = name, a = a, b = b, truth = truth, expr2 = expr2)) 46 | stopifnot(all.equal(expr2, truth)) 47 | } 48 | } 49 | } 50 | } 51 | 52 | message("*** bquote_compile() & bquote_apply() ... DONE") 53 | -------------------------------------------------------------------------------- /inst/testme/test-cancel.R: -------------------------------------------------------------------------------- 1 | #' @tags cancel 2 | #' @tags detritus-files 3 | #' @tags detritus-connections 4 | #' @tags sequential multisession multicore 5 | 6 | library(future) 7 | options(future.debug = FALSE) 8 | 9 | strategies <- supportedStrategies() 10 | #strategies <- setdiff(strategies, "sequential") 11 | 12 | for (strategy in strategies) { 13 | message(sprintf("plan('%s') ...", strategy)) 14 | plan(strategy) 15 | 16 | n0 <- nbrOfFreeWorkers() 17 | message(" Number of free workers: ", n0) 18 | 19 | message(" Create a future") 20 | f <- future({ Sys.sleep(1.0); 42 }) 21 | stopifnot( 22 | f[["state"]] == "running" || 23 | (f[["state"]] == "finished" && inherits(f, "SequentialFuture")) 24 | ) 25 | stopifnot( 26 | !resolved(f) || 27 | (resolved(f) && f[["state"]] == "finished") 28 | ) 29 | 30 | message(" Cancel future, which also interrupts the future, if supported") 31 | f <- cancel(f) 32 | stopifnot({ 33 | f[["state"]] %in% c("canceled", "interrupted") || 34 | (f[["state"]] == "finished" && inherits(f, "SequentialFuture")) 35 | }) 36 | 37 | n <- nbrOfFreeWorkers() 38 | message(" Number of free workers (after cancel + interupt): ", n) 39 | 40 | message(" Check if canceled + interrupted future is resolved") 41 | f <- resolve(f) 42 | stopifnot(resolved(f)) 43 | stopifnot({ 44 | f[["state"]] %in% c("canceled", "interrupted") || 45 | (f[["state"]] == "finished" && inherits(f, "SequentialFuture")) 46 | }) 47 | 48 | n <- nbrOfFreeWorkers() 49 | message(" Number of free workers (after resolve): ", n) 50 | 51 | message(" Force collect of canceled future (to free up worker)") 52 | ## Force collection of the future 53 | r <- tryCatch(result(f), error = identity) 54 | n <- nbrOfFreeWorkers() 55 | message("Number of free workers (after result): ", n) 56 | stopifnot(n == n0) 57 | 58 | message(" And cancel the same future multiple times") 59 | for (kk in 1:10) { 60 | f <- cancel(f) 61 | } 62 | 63 | message(" Create another future") 64 | ## Create another future 65 | f <- future(42) 66 | v <- value(f) 67 | n <- nbrOfFreeWorkers() 68 | message(" Number of free workers (after result): ", n) 69 | stopifnot(n == n0) 70 | 71 | message(sprintf("plan('%s') .. done", strategy)) 72 | } 73 | 74 | message("Shut down future backend") 75 | plan(sequential) 76 | gc() 77 | -------------------------------------------------------------------------------- /inst/testme/test-capture_journals.R: -------------------------------------------------------------------------------- 1 | #' @tags journals 2 | #' @tags multisession 3 | 4 | library(future) 5 | 6 | capture_journals <- future:::capture_journals 7 | 8 | message("*** capture_journals() ...") 9 | 10 | slow_fcn <- function(x) { 11 | Sys.sleep(0.01 * (1 + 1/x)) 12 | } 13 | 14 | plan(multisession, workers = 2) 15 | js <- capture_journals({ 16 | fs <- lapply(3:1, FUN = function(x) future(slow_fcn(x))) 17 | vs <- value(fs) 18 | }) 19 | print(js) 20 | stopifnot( 21 | is.list(js), 22 | all(vapply(js, FUN = is.data.frame, FUN.VALUE = NA)) 23 | ) 24 | 25 | ## Shut down parallel workers 26 | plan(sequential) 27 | 28 | message("*** capture_journals() ... done") 29 | 30 | 31 | message("*** summary() of FutureJournal ...") 32 | 33 | js <- do.call(rbind, js) 34 | print(js) 35 | 36 | stats <- summary(js) 37 | print(stats) 38 | 39 | message("*** summary() of FutureJournal ... done") 40 | -------------------------------------------------------------------------------- /inst/testme/test-cluster-connection-clashes.R: -------------------------------------------------------------------------------- 1 | ## This test asserts that two R connections part of PSOCK cluster nodes 2 | ## are identified as different, although they share the same connection 3 | ## index. This is required in order to work around a bug in R [1] 4 | ## [1] https://github.com/HenrikBengtsson/Wishlist-for-R/issues/81 5 | library(future) 6 | 7 | message("all.equal() for connection ...") 8 | con1 <- rawConnection(raw()) 9 | close(con1) 10 | 11 | con2 <- rawConnection(raw()) 12 | close(con2) 13 | 14 | stopifnot(!isTRUE(all.equal(con1, con2))) 15 | message("all.equal() for connection ... done") 16 | 17 | 18 | message("all.equal() for cluster backend ...") 19 | 20 | for (kk in 1:3) { 21 | message("Iteration #", kk) 22 | cl <- parallel::makeCluster(1) 23 | plan(cluster, workers = cl) 24 | 25 | fs <- lapply(1:2, FUN = future) 26 | 27 | vs <- value(fs) 28 | parallel::stopCluster(cl) 29 | } 30 | 31 | plan(sequential) 32 | 33 | message("all.equal() for cluster backend ... done") 34 | -------------------------------------------------------------------------------- /inst/testme/test-demo-fibonacci.R: -------------------------------------------------------------------------------- 1 | #' @tags demo fibonacci 2 | #' @tags sequential 3 | 4 | library(future) 5 | plan(sequential) 6 | options(future.debug = FALSE) 7 | 8 | message("*** Fibonacci demo of the 'future' package ...") 9 | # Temporarily protect against non-default R_FUTURE_PLAN 10 | oopts <- options(future.plan = NULL) 11 | demo("fibonacci", package = "future", ask = FALSE) 12 | options(oopts) 13 | message("*** Fibonacci demo of the 'future' package ... DONE") 14 | -------------------------------------------------------------------------------- /inst/testme/test-demo-mandelbrot.R: -------------------------------------------------------------------------------- 1 | #' @tags demo mandelbrot 2 | #' @tags sequential cluster multisession multicore 3 | 4 | library(future) 5 | 6 | ## Avoid 'Error: C stack usage 7971940 is too close to the limit' 7 | ## on R (< 4.1.0) 8 | if (getRversion() < "4.1") options(future.debug = FALSE) 9 | 10 | message("*** Mandelbrot demo of the 'future' package ...") 11 | options(future.demo.mandelbrot.nrow = 2L) 12 | options(future.demo.mandelbrot.resolution = 50L) 13 | options(future.demo.mandelbrot.delay = FALSE) 14 | 15 | for (cores in 1:availCores) { 16 | message(sprintf("Testing with %d cores ...", cores)) 17 | options(mc.cores = cores) 18 | 19 | for (strategy in supportedStrategies(cores)) { 20 | message(sprintf("- plan('%s') ...", strategy)) 21 | plan(strategy) 22 | demo("mandelbrot", package = "future", ask = FALSE) 23 | message(sprintf("- plan('%s') ... DONE", strategy)) 24 | } 25 | 26 | message(sprintf("Testing with %d cores ... DONE", cores)) 27 | } ## for (cores ...) 28 | message("*** Mandelbrot demo of the 'future' package ... DONE") 29 | 30 | -------------------------------------------------------------------------------- /inst/testme/test-error_on_warn_2.R: -------------------------------------------------------------------------------- 1 | #' @tags warn2 2 | #' @tags error 3 | #' @tags future 4 | #' @tags sequential multisession multicore 5 | 6 | library(future) 7 | 8 | message("*** options(warn = 2) relays an error ...") 9 | 10 | for (strategy in supportedStrategies()) { 11 | message("Type of future: ", strategy) 12 | plan(strategy) 13 | 14 | f <- future({ 15 | stopifnot(getOption("warn") == 0) 16 | oopts <- options(warn = 2) 17 | on.exit(options(oopts)) 18 | log(-1) 19 | 42L 20 | }) 21 | 22 | r <- result(f) 23 | 24 | y <- tryCatch(value(f), error = identity) 25 | print(y) 26 | stopifnot(inherits(y, "error")) 27 | } ## for (strategy ...) 28 | 29 | message("*** options(warn = 2) relays an error ... done") 30 | -------------------------------------------------------------------------------- /inst/testme/test-future,labels.R: -------------------------------------------------------------------------------- 1 | #' @tags labels 2 | #' @tags sequential multisession multicore 3 | 4 | library(future) 5 | 6 | message("*** Futures - labels ...") 7 | 8 | strategies <- supportedStrategies() 9 | 10 | for (strategy in strategies) { 11 | message(sprintf("- plan('%s') ...", strategy)) 12 | plan(strategy) 13 | 14 | for (label in list(NULL, sprintf("strategy = %s", strategy))) { 15 | fcn <- get(strategy, mode = "function") 16 | stopifnot(inherits(fcn, strategy)) 17 | 18 | f <- future(42, label = label) 19 | print(f) 20 | stopifnot(identical(f[["label"]], label)) 21 | v <- value(f) 22 | stopifnot(v == 42) 23 | 24 | v %<-% { 42 } %label% label 25 | f <- futureOf(v) 26 | print(f) 27 | stopifnot(identical(f[["label"]], label)) 28 | stopifnot(v == 42) 29 | 30 | } ## for (label ...) 31 | 32 | message(sprintf("- plan('%s') ... DONE", strategy)) 33 | } ## for (strategy ...) 34 | 35 | message("*** Futures - labels ... DONE") 36 | 37 | -------------------------------------------------------------------------------- /inst/testme/test-future.R: -------------------------------------------------------------------------------- 1 | #' @tags future 2 | #' @tags sequential 3 | 4 | library(future) 5 | 6 | message("*** future() ...") 7 | 8 | message("*** future() w/ lazy = TRUE ...") 9 | 10 | f <- future({ 11 | 42L 12 | }, lazy = TRUE) 13 | 14 | print(resolved(f)) 15 | y <- value(f) 16 | print(y) 17 | stopifnot(y == 42L) 18 | 19 | message("*** future() w/ lazy = TRUE ... DONE") 20 | 21 | message("*** future() w/ lazy = TRUE in local() ...") 22 | 23 | local({ 24 | a <- 42L 25 | f <- future({ a }, lazy = TRUE) 26 | a <- 0L 27 | y <- value(f) 28 | print(y) 29 | stopifnot(y == 42L) 30 | }) 31 | 32 | message("*** future() w/ lazy = TRUE in local() ... DONE") 33 | 34 | message("*** future() w/ gc = TRUE ...") 35 | 36 | f <- future(42L, gc = TRUE, lazy = TRUE) 37 | print(f) 38 | y <- value(f) 39 | print(y) 40 | stopifnot(y == 42L) 41 | 42 | message("*** future() w/ gc = TRUE ... DONE") 43 | message("*** future() ... DONE") 44 | 45 | message("*** future() ...") 46 | 47 | f <- future({ 48 | 42L 49 | }, lazy = TRUE) 50 | 51 | print(resolved(f)) 52 | y <- value(f) 53 | print(y) 54 | stopifnot(y == 42L) 55 | 56 | 57 | message("*** future() w/ gc = TRUE ...") 58 | 59 | f <- future(42L, gc = TRUE, lazy = TRUE) 60 | print(f) 61 | y <- value(f) 62 | print(y) 63 | stopifnot(y == 42L) 64 | 65 | message("*** future() w/ gc = TRUE ... DONE") 66 | 67 | 68 | message("*** future() - exceptions ...") 69 | 70 | target <- list(name = "", envir = new.env(), code = "Yo!", exists = TRUE) 71 | res <- tryCatch(get_future(target, mustExist = TRUE), error = identity) 72 | stopifnot(inherits(res, "error")) 73 | 74 | message("*** future() - exceptions ... DONE") 75 | 76 | message("*** future() ... DONE") 77 | 78 | -------------------------------------------------------------------------------- /inst/testme/test-futureAssign_OP_with_environment.R: -------------------------------------------------------------------------------- 1 | #' @tags futureAssign 2 | #' @tags environment 3 | #' @tags sequential multisession multicore 4 | 5 | library(future) 6 | 7 | message("*** %<-% to environment ...") 8 | 9 | ## - - - - - - - - - - - - - - - - - - - - - - - - - - - - 10 | ## Async delayed assignment (infix operator) 11 | ## - - - - - - - - - - - - - - - - - - - - - - - - - - - - 12 | z <- new.env() 13 | stopifnot(length(names(z)) == 0L) 14 | 15 | message("*** %<-% to environment: Assign by index (not allowed)") 16 | res <- try(z[[1]] %<-% { 2 } %lazy% TRUE, silent = TRUE) 17 | stopifnot(inherits(res, "try-error")) 18 | 19 | message("*** %<-% to environment: Assign by name (new)") 20 | z$B %<-% { TRUE } %lazy% TRUE 21 | stopifnot(length(z) == 2) # sic! 22 | stopifnot("B" %in% ls(z)) 23 | 24 | y <- as.list(z) 25 | str(y) 26 | stopifnot(length(y) == 1) 27 | stopifnot(identical(names(y), "B")) 28 | 29 | 30 | message("*** %<-% to environment: Potential task name clashes") 31 | u <- new.env() 32 | u$a %<-% { 1 } %lazy% TRUE 33 | stopifnot(length(u) == 2) 34 | stopifnot("a" %in% names(u)) 35 | fu <- futureOf(u$a) 36 | 37 | v <- new.env() 38 | v$a %<-% { 2 } %lazy% TRUE 39 | stopifnot(length(v) == 2) 40 | stopifnot("a" %in% names(v)) 41 | fv <- futureOf(v$a) 42 | stopifnot(!identical(fu, fv)) 43 | 44 | fu <- futureOf(u$a) 45 | stopifnot(!identical(fu, fv)) 46 | 47 | stopifnot(identical(u$a, 1)) 48 | stopifnot(identical(v$a, 2)) 49 | 50 | message("*** %<-% to environment ... DONE") 51 | 52 | -------------------------------------------------------------------------------- /inst/testme/test-futureAssign_OP_with_listenv.R: -------------------------------------------------------------------------------- 1 | #' @tags futureAssign 2 | #' @tags listenv 3 | #' @tags sequential multisession multicore 4 | 5 | library(future) 6 | library(listenv) 7 | 8 | message("*** %<-% to listenv ...") 9 | 10 | ## - - - - - - - - - - - - - - - - - - - - - - - - - - - - 11 | ## Future assignment via infix operator 12 | ## - - - - - - - - - - - - - - - - - - - - - - - - - - - - 13 | z <- listenv() 14 | stopifnot(length(names(z)) == 0) 15 | 16 | message("*** %<-% to listenv: Assign by index") 17 | z[[1]] %<-% { 2 } %lazy% TRUE 18 | stopifnot(length(z) == 1) 19 | stopifnot(length(names(z)) == 0) 20 | 21 | z[[1]] %<-% { 2 } %lazy% TRUE 22 | stopifnot(length(z) == 1) 23 | stopifnot(length(names(z)) == 0) 24 | 25 | z[[4]] %<-% { "async!" } %lazy% TRUE 26 | stopifnot(length(z) == 4) 27 | stopifnot(length(names(z)) == 0) 28 | 29 | message("*** %<-% to listenv: Update names") 30 | names(z) <- c("A", "B", "C", "D") 31 | stopifnot(identical(names(z), c("A", "B", "C", "D"))) 32 | 33 | 34 | message("*** %<-% to listenv: Assign by name (existing)") 35 | z$B %<-% { TRUE } %lazy% TRUE 36 | stopifnot(length(z) == 4) 37 | stopifnot(identical(names(z), c("A", "B", "C", "D"))) 38 | 39 | y <- as.list(z) 40 | str(y) 41 | stopifnot(length(y) == 4) 42 | stopifnot(identical(names(y), c("A", "B", "C", "D"))) 43 | 44 | 45 | message("*** %<-% to listenv: Asserting no name clashes among futures") 46 | u <- listenv() 47 | u$a %<-% { 1 } %lazy% TRUE 48 | stopifnot(identical(names(u), "a")) 49 | fu <- futureOf(u$a) 50 | 51 | v <- listenv() 52 | v$a %<-% { 2 } %lazy% TRUE 53 | stopifnot(identical(names(v), "a")) 54 | fv <- futureOf(v$a) 55 | stopifnot(!identical(fu, fv)) 56 | 57 | fu <- futureOf(u$a) 58 | stopifnot(!identical(fu, fv)) 59 | 60 | stopifnot(identical(u$a, 1)) 61 | stopifnot(identical(v$a, 2)) 62 | 63 | 64 | message("*** %<-% to listenv: multiple dimensions ...") 65 | 66 | x0 <- list() 67 | length(x0) <- 6 68 | dim(x0) <- c(3, 2) 69 | 70 | x <- listenv() 71 | length(x) <- 6 72 | dim(x) <- c(3, 2) 73 | 74 | for (cc in 1:ncol(x)) { 75 | for (rr in 1:nrow(x)) { 76 | x0[[rr, cc]] <- sprintf("(%s, %s)", rr, cc) 77 | x[[rr, cc]] %<-% sprintf("(%s, %s)", rr, cc) %lazy% TRUE 78 | } 79 | } 80 | 81 | y <- as.list(x) 82 | dim(y) <- dim(x) 83 | stopifnot(identical(y, x0)) 84 | 85 | message("*** %<-% to listenv: multiple dimensions ... DONE") 86 | 87 | message("*** %<-% to listenv ... DONE") 88 | 89 | -------------------------------------------------------------------------------- /inst/testme/test-futureOf.R: -------------------------------------------------------------------------------- 1 | #' @tags futureOf 2 | #' @tags listenv environment 3 | #' @tags sequential 4 | 5 | library(future) 6 | library(listenv) 7 | 8 | message("*** futureOf() ...") 9 | 10 | a %<-% { 1 } %lazy% TRUE 11 | 12 | f1 <- futureOf("a") 13 | print(f1) 14 | f2 <- futureOf(a) 15 | print(f2) 16 | stopifnot(identical(f2, f1)) 17 | 18 | ## Get all futures in the current environment 19 | fs <- futureOf(drop = TRUE) 20 | print(fs) 21 | stopifnot( 22 | is.list(fs), 23 | length(fs) == 3L, 24 | all(names(fs) %in% c("a", "f1", "f2")) 25 | ) 26 | 27 | ## Non-existing object 28 | res <- tryCatch(futureOf("non-exiting-object", mustExist = TRUE), error = identity) 29 | stopifnot(inherits(res, "error")) 30 | 31 | message("*** futureOf() ... DONE") 32 | 33 | -------------------------------------------------------------------------------- /inst/testme/test-futureSessionInfo.R: -------------------------------------------------------------------------------- 1 | #' @tags futureSessionInfo 2 | #' @tags sequential 3 | 4 | library(future) 5 | 6 | message("*** futureSessionInfo() ...") 7 | 8 | message(" - test = FALSE") 9 | futureSessionInfo(test = FALSE) 10 | 11 | message(" - test = TRUE") 12 | futureSessionInfo(test = TRUE) 13 | 14 | message("*** futureSessionInfo() ... DONE") 15 | 16 | -------------------------------------------------------------------------------- /inst/testme/test-globals,NSE.R: -------------------------------------------------------------------------------- 1 | #' @tags globals 2 | #' @tags nse 3 | #' @tags listenv 4 | #' @tags nested-futures 5 | #' @tags sequential multisession multicore 6 | 7 | library(future) 8 | library(listenv) 9 | options(future.debug = FALSE) 10 | 11 | message("*** Globals w/ non-standard evaluation (NSE) ...") 12 | 13 | data <- data.frame(x = 1:5, y = 1:5) 14 | v0 <- subset(data, x < 3)$y 15 | 16 | for (strategy in supportedStrategies()) { 17 | message(sprintf("- Strategy: %s ...", strategy)) 18 | 19 | plan(strategy) 20 | 21 | ## Assert option is passed on to future 22 | options(future.globals.onMissing = "error") 23 | opt1 %<-% getOption("future.globals.onMissing") 24 | stopifnot(identical(opt1, "error")) 25 | 26 | options(future.globals.onMissing = "ignore") 27 | opt2 %<-% getOption("future.globals.onMissing") 28 | stopifnot(identical(opt2, "ignore")) 29 | 30 | options(future.globals.onMissing = "error") 31 | res <- try({ v1 %<-% subset(data, x < 3)$y }, silent = TRUE) 32 | stopifnot(inherits(res, "try-error")) 33 | 34 | options(future.globals.onMissing = "ignore") 35 | v2 %<-% subset(data, x < 3)$y 36 | stopifnot(identical(v2, v0)) 37 | 38 | plan(sequential) 39 | 40 | 41 | ## Nested futures (requires option is passed on to future) 42 | plan(list(sequential, strategy)) 43 | options(future.globals.onMissing = "ignore") 44 | v3 %<-% { 45 | a %<-% subset(data, x < 3)$y 46 | a 47 | } %lazy% TRUE 48 | stopifnot(identical(v3, v0)) 49 | 50 | options(future.globals.onMissing = NULL) 51 | 52 | 53 | ## Shut down nested backend 54 | local({ 55 | ## FIXME: plan() should do this for us /HB 2025-03-28a 56 | oopts <- options(future.connections.onMisuse = "warning") 57 | on.exit(options(oopts)) 58 | void %<-% { plan(sequential); TRUE } 59 | stopifnot(isTRUE(void)) 60 | }) 61 | 62 | plan(sequential) 63 | 64 | message(sprintf("- Strategy: %s ... DONE", strategy)) 65 | } 66 | 67 | 68 | message("*** Globals w/ non-standard evaluation (NSE) ... DONE") 69 | -------------------------------------------------------------------------------- /inst/testme/test-globals,S4methods.R: -------------------------------------------------------------------------------- 1 | #' @tags globals s4 2 | #' @tags sequential multisession multicore 3 | 4 | library(future) 5 | library(methods) 6 | 7 | message("*** Globals - S4 methods ...") 8 | 9 | setGeneric("my_fcn", function(x) standardGeneric("my_fcn")) 10 | setMethod("my_fcn", signature(x = "numeric"), function(x) { -x }) 11 | org_my_fcn <- my_fcn 12 | 13 | truth <- my_fcn(3) 14 | 15 | for (strategy in supportedStrategies()) { 16 | message("Type of future: ", strategy) 17 | plan(strategy) 18 | 19 | ## Assert that S4 generic function 'my_fcn()' is exported 20 | f <- future({ my_fcn }, lazy = TRUE) 21 | rm(list = "my_fcn") 22 | v <- value(f) 23 | print(v) 24 | stopifnot( 25 | is.function(v), 26 | inherits(v, class(org_my_fcn)[1]) 27 | ) 28 | my_fcn <- org_my_fcn 29 | 30 | ## FIXME: 31 | ## Just like S3 methods, S4 methods are not picked up 32 | ## https://github.com/futureverse/future/issues/615 33 | f <- future({ my_fcn(3) }, lazy = TRUE) 34 | rm(list = "my_fcn") 35 | v <- tryCatch(value(f), error = identity) 36 | print(v) 37 | if (isTRUE(getOption("future.globals.keepWhere", TRUE))) { 38 | message("future.globals.keepWhere=TRUE") 39 | stopifnot(identical(v, truth)) 40 | } else { 41 | message("future.globals.keepWhere=FALSE") 42 | stopifnot(inherits(v, "error")) 43 | } 44 | my_fcn <- org_my_fcn 45 | 46 | plan(sequential) 47 | } 48 | 49 | message("*** Globals - S4 methods ... DONE") 50 | 51 | -------------------------------------------------------------------------------- /inst/testme/test-globals,packages.R: -------------------------------------------------------------------------------- 1 | #' @tags globals packages load attach 2 | #' @tags sequential multisession multicore 3 | 4 | library(future) 5 | options(future.debug = FALSE) 6 | 7 | message("*** Automatically attaching packages, if attached in parent ...") 8 | 9 | for (strategy in supportedStrategies()) { 10 | message(sprintf("- Strategy: %s ...", strategy)) 11 | 12 | plan(strategy) 13 | 14 | for (attach in c(FALSE, TRUE)) { 15 | message(sprintf("- Attach 'listenv': %s", attach)) 16 | if (attach) { 17 | library(listenv) 18 | } else { 19 | if ("package:listenv" %in% search()) { 20 | detach(package:listenv) 21 | } 22 | } 23 | message("Attached packages: ", paste(search(), collapse = ", ")) 24 | 25 | f <- future({ 26 | env <- listenv::listenv() 27 | env[[1]] <- 42L 28 | ## 'get_variable()' is a global variable that should 29 | ## only work if 'listenv' is attached, which it will 30 | ## only be if it is attached in the parent R session 31 | name <- get_variable(env, 1L) 32 | 42L 33 | }) 34 | 35 | v <- tryCatch(value(f), error = identity) 36 | print(v) 37 | if (attach) { 38 | stopifnot(v == 42L) 39 | } else { 40 | stopifnot(inherits(v, "error")) 41 | } 42 | } ## for (attach in ...) 43 | 44 | message(sprintf("- Strategy: %s ... DONE", strategy)) 45 | } 46 | 47 | message("*** Automatically attaching packages, if attached in parent ... done") 48 | -------------------------------------------------------------------------------- /inst/testme/test-globals,resolve.R: -------------------------------------------------------------------------------- 1 | #' @tags globals resolve 2 | #' @tags listenv 3 | #' @tags multisession 4 | #' @tags skip_on_cran 5 | 6 | library(future) 7 | library(listenv) 8 | 9 | oopts <- c(oopts, options(future.globals.resolve = TRUE)) 10 | setTimeLimit(cpu = 10, elapsed = 10, transient = TRUE) 11 | 12 | message("*** Tricky use cases related to globals (part 2) ...") 13 | 14 | ## Allow for two background processes 15 | plan(multisession, workers = 2L) 16 | 17 | env <- new.env() 18 | 19 | ## Create future #1 (consumes background process #1) 20 | env$a %<-% { 5 } 21 | 22 | ## Create future #2 (consumes background process #2) 23 | b %<-% { "a" } 24 | 25 | ## Resolve future #2 (frees up background process #2) 26 | message(sprintf("b = %s\n", sQuote(b))) 27 | 28 | ## Create future #3 (consumes background process #2) 29 | ## THIS IS THE TRICKY PART: 30 | ## Two globals are identified `env` and `b` and both are resolved. 31 | ## However, object `env[[b]]` (here element `a` of environment `env`) 32 | ## is not touched and therefore not resolved (since it is a future) 33 | ## unless environment `env` is resolved recursively. (Issue #49) 34 | y %<-% { env[[b]] } 35 | 36 | ## Resolve future #3 37 | message(sprintf("y = %s\n", y)) 38 | 39 | ## Resolve future #1 if not already done 40 | str(as.list(env)) 41 | 42 | ## Create future #4 43 | ## Since future #1 is resolved it will work at this point 44 | y %<-% { env[[b]] } 45 | ## Resolve future #4 46 | message(sprintf("y = %s\n", y)) 47 | 48 | message("*** Tricky use cases related to globals (part 2) ... DONE") 49 | 50 | ## Cleanup 51 | setTimeLimit() 52 | -------------------------------------------------------------------------------- /inst/testme/test-globals,toolarge.R: -------------------------------------------------------------------------------- 1 | #' @tags globals too-large 2 | #' @tags multisession 3 | 4 | library(future) 5 | 6 | message("*** Globals - too large ...") 7 | 8 | a <- integer(length = 1000) 9 | ooptsT <- options(future.globals.maxSize = object.size(a) - 100L) 10 | limit <- getOption("future.globals.maxSize") 11 | cat(sprintf("Max total size of globals: %g bytes\n", limit)) 12 | 13 | plan(multisession, workers = 2L) 14 | print(plan("backend")) 15 | 16 | exprs <- list( 17 | A = substitute({ a }, env = list()), 18 | B = substitute({ a * b }, env = list()), 19 | C = substitute({ a * b * c }, env = list()), 20 | D = substitute({ a * b * c * d }, env = list()), 21 | E = substitute({ a * b * c * d * e }, env = list()) 22 | ) 23 | 24 | a <- integer(length = 1000) 25 | b <- integer(length = 900) 26 | c <- integer(length = 800) 27 | d <- integer(length = 700) 28 | e <- integer(length = 1) 29 | 30 | for (name in names(exprs)) { 31 | message(sprintf("Expression %s:", name)) 32 | expr <- exprs[[name]] 33 | print(expr) 34 | res <- tryCatch({ 35 | f <- future(expr, substitute = FALSE) 36 | }, error = function(ex) ex) 37 | print(res) 38 | stopifnot(inherits(res, "error")) 39 | msg <- conditionMessage(res) 40 | stopifnot(grepl("exceeds the maximum allowed size", msg)) 41 | } 42 | 43 | message("*** Globals - too large ... DONE") 44 | 45 | -------------------------------------------------------------------------------- /inst/testme/test-globalsOf,tweaks.R: -------------------------------------------------------------------------------- 1 | #' @tags globals 2 | #' @tags tweakExpression 3 | 4 | library(future) 5 | library(globals) 6 | 7 | 8 | message("*** tweakExpression() ...") 9 | 10 | expr <- substitute({ a <<- 1; b <- 2; 3 ->> c }, env = list()) 11 | print(expr) 12 | exprT <- tweakExpression(expr) 13 | print(exprT) 14 | 15 | 16 | b <- 2 17 | exprs <- list( 18 | A = substitute({ a <- b; }, env = list()), 19 | B = substitute({ a <- b; b <- 1 }, env = list()), 20 | C = substitute({ a <- 1; a <- 2 }, env = list()), 21 | D = substitute({ a <<- 1; a <- 2 }, env = list()), 22 | E = substitute({ a <<- 1 }, env = list()) 23 | ) 24 | 25 | truth <- list( 26 | A = "b", 27 | B = "b", 28 | C = character(0L), 29 | D = character(0L), 30 | E = character(0L) 31 | ) 32 | 33 | 34 | for (kk in seq_along(exprs)) { 35 | name <- names(exprs)[kk] 36 | expr <- exprs[[kk]] 37 | cat(sprintf("Expression #%d ('%s'):", kk, name)) 38 | print(expr) 39 | globals <- globalsOf(expr, tweak = tweakExpression, recursive = TRUE) 40 | globals <- cleanup(globals) 41 | str(globals) 42 | stopifnot(identical(names(globals), truth[[name]])) 43 | } 44 | 45 | message("*** tweakExpression() ... DONE") 46 | 47 | -------------------------------------------------------------------------------- /inst/testme/test-interrupts-from-worker-itself.R: -------------------------------------------------------------------------------- 1 | #' @tags worker-interrupt 2 | #' @tags detritus-files 3 | #' @tags multisession multicore 4 | 5 | library(future) 6 | options(future.debug = FALSE) 7 | 8 | strategies <- supportedStrategies() 9 | 10 | ## Signalling SIGINT to an R future process might end up 11 | ## terminating the whole R process. Because of that, we 12 | ## might get a FutureError, because we can no longer 13 | ## communicate with the worker. 14 | ## 15 | ## Because of this, we skip interrupt testing 'sequential', 16 | ## because it might terminate the R process running this unit test. 17 | ## Comment: This has happend on win-devel, but also R 4.3.0 on Linux. 18 | strategies <- setdiff(strategies, "sequential") 19 | 20 | for (strategy in strategies) { 21 | message(sprintf("- plan('%s') ...", strategy)) 22 | plan(strategy) 23 | 24 | f <- future({ 25 | message("Hello world!") 26 | cat("Hi there\n") 27 | res <- tools::pskill(Sys.getpid(), signal = tools::SIGINT) 28 | cat(sprintf("tools::pskill() value: %s\n", res)) 29 | 42 30 | }) 31 | r <- tryCatch({ 32 | result(f) 33 | }, FutureError = identity) 34 | stopifnot( 35 | # (i) Ideally, regular results, but .. 36 | inherits(r, "FutureResult") || 37 | # (ii) SIGINT might crash the R parallel worker 38 | inherits(r, "FutureError") 39 | ) 40 | 41 | v <- tryCatch({ 42 | value(f) 43 | }, FutureError = identity) 44 | print(v) 45 | 46 | ## A future interrupting itself is not supported on all backends 47 | stopifnot( 48 | # (i) Ideally the SIGINT interrupt condition is caught, but ... 49 | inherits(v, "FutureInterruptError") || 50 | # (ii) it might crash the R parallel worker, e.g. communication 51 | # channels are shutdown ... 52 | inherits(v, "FutureError") || 53 | # (iii) ... or have no effect at all 54 | v == 42 55 | ) 56 | 57 | ## It should always be possible to reset 58 | f <- reset(f) 59 | print(f) 60 | stopifnot( 61 | f[["lazy"]], 62 | f[["state"]] == "created" 63 | ) 64 | } 65 | 66 | -------------------------------------------------------------------------------- /inst/testme/test-makeClusterFuture.R: -------------------------------------------------------------------------------- 1 | if (getRversion() >= "4.4.0") { 2 | library(future) 3 | library(parallel) 4 | 5 | a <- 42 6 | 7 | FUN <- function(x) { 8 | message("Process ID: ", Sys.getpid()) 9 | list(a = a, mean = mean(rnorm(n = x))) 10 | } 11 | 12 | message("makeCluster():") 13 | plan(multisession) 14 | cl <- makeCluster(2) 15 | set.seed(42) 16 | clusterSetRNGStream(cl) 17 | clusterExport(cl, "a") 18 | y <- list() 19 | for (kk in 1:3) y[[kk]] <- parLapply(cl, 11:13, FUN) 20 | str(y) 21 | stopCluster(cl) 22 | y_truth <- y 23 | 24 | message("makeClusterFuture():") 25 | plan(multisession, workers = 2) 26 | cl <- makeClusterFuture() 27 | set.seed(42) 28 | clusterSetRNGStream(cl) 29 | clusterExport(cl, "a") 30 | y <- list() 31 | for (kk in 1:3) y[[kk]] <- parLapply(cl, 11:13, FUN) 32 | str(y) 33 | plan(sequential) 34 | 35 | stopifnot(identical(y, y_truth)) 36 | } 37 | -------------------------------------------------------------------------------- /inst/testme/test-mandelbrot.R: -------------------------------------------------------------------------------- 1 | #' @tags demo mandelbrot 2 | #' @tags sequential 3 | 4 | library(future) 5 | 6 | message("mandelbrot() ...") 7 | 8 | counts <- mandelbrot(xmid = -0.75, ymid = 0.0, side = 3.0, resolution = 100L) 9 | img <- as.raster(counts) 10 | plot(img) 11 | plot(counts) 12 | 13 | message("mandelbrot() ... DONE") 14 | 15 | -------------------------------------------------------------------------------- /inst/testme/test-misuse-connections.R: -------------------------------------------------------------------------------- 1 | #' @tags connections 2 | #' @tags misuse 3 | #' @tags sequential multisession multicore 4 | 5 | library(future) 6 | options( 7 | future.debug = FALSE, 8 | future.globals.onReference = "ignore" ## because we return a connection 9 | ) 10 | 11 | for (onMisuse in c("ignore", "warning", "error")) { 12 | message("onMisuse = ", sQuote(onMisuse)) 13 | options(future.connections.onMisuse = onMisuse) 14 | 15 | cons_before <- getAllConnections() 16 | 17 | f <- future({ 18 | con <- textConnection("abc") 19 | ## Return connection, to avoid it being 20 | ## garbage collected before we return 21 | structure(42L, con = con) 22 | }) 23 | r <- result(f) 24 | diff <- r[["misuseConnections"]] 25 | message("Misused connections:") 26 | v <- tryCatch({ 27 | value(f) 28 | }, condition = identity) 29 | str(v) 30 | 31 | if (onMisuse == "error") { 32 | if (inherits(v, "condition")) message(conditionMessage(v)) 33 | stopifnot(inherits(v, "FutureError")) 34 | } else if (onMisuse == "warning") { 35 | if (inherits(v, "condition")) message(conditionMessage(v)) 36 | stopifnot(inherits(v, "FutureWarning")) 37 | } else { 38 | message("None") 39 | if (inherits(v, "condition")) message(conditionMessage(v)) 40 | stopifnot( 41 | !inherits(v, "condition"), 42 | v == 42L 43 | ) 44 | } 45 | 46 | ## Close stray connection? 47 | cons_diff <- setdiff(getAllConnections(), cons_before) 48 | message("Closing stray connections: ", paste(cons_diff, collapse = ", ")) 49 | lapply(cons_diff, FUN = function(idx) { 50 | tryCatch(close(getConnection(idx)), error = identity) 51 | }) 52 | } 53 | 54 | -------------------------------------------------------------------------------- /inst/testme/test-mpi.R: -------------------------------------------------------------------------------- 1 | #' @tags mpi 2 | #' @tags cluster 3 | #' @tags skip_on_cran 4 | 5 | library(future) 6 | stopCluster <- parallel::stopCluster 7 | 8 | message("*** MPI ...") 9 | 10 | pkg <- "Rmpi" 11 | if (fullTest && requireNamespace(pkg, quietly = TRUE)) { 12 | cl <- makeClusterMPI(availableCores()) 13 | str(cl) 14 | 15 | plan(cluster, workers = cl) 16 | 17 | fs <- lapply(1:2, FUN = function(x) future({ 18 | printf("Hostname: %s\n", Sys.info()[["nodename"]]) 19 | printf("PID: %d\n", Sys.getpid()) 20 | Sys.sleep(0.5) 21 | x^2 22 | })) 23 | print(fs) 24 | vs <- value(fs) 25 | print(vs) 26 | stopifnot(all(unlist(vs) == c(1, 4))) 27 | 28 | stopCluster(cl) 29 | str(cl) 30 | } 31 | 32 | message("*** MPI ... DONE") 33 | 34 | -------------------------------------------------------------------------------- /inst/testme/test-multicore,worker-termination.R: -------------------------------------------------------------------------------- 1 | #' @tags worker-killed 2 | #' @tags multicore 3 | #' 4 | library(future) 5 | 6 | message("*** multicore() - terminating workers ...") 7 | 8 | if (supportsMulticore() && availableCores("multicore") >= 2L) { 9 | plan(multicore, workers = 2L) 10 | 11 | all <- nbrOfWorkers() 12 | free <- nbrOfFreeWorkers() 13 | stopifnot( 14 | nbrOfWorkers() == 2L, 15 | nbrOfFreeWorkers() == 2L 16 | ) 17 | 18 | ## Force R worker to quit 19 | f <- future({ tools::pskill(pid = Sys.getpid()) }) 20 | res <- tryCatch(value(f), error = identity) 21 | print(res) 22 | print(conditionMessage(res)) 23 | stopifnot(inherits(res, "FutureError")) 24 | 25 | stopifnot(nbrOfWorkers() == all) 26 | ## Assert that the worker slot was released? Not always possible 27 | str(f$job) 28 | cat(sprintf("nbrOfFreeWorkers(): %d\n", nbrOfFreeWorkers())) 29 | if (!is.na(f$job$alive) && !f$job$alive) { 30 | stopifnot(nbrOfFreeWorkers() == free) 31 | } else { 32 | stopifnot(nbrOfFreeWorkers() <= free) 33 | } 34 | } 35 | 36 | message("*** multicore() - terminating workers ... DONE") 37 | 38 | -------------------------------------------------------------------------------- /inst/testme/test-non-exportable,connections.R: -------------------------------------------------------------------------------- 1 | #' @tags globals non-exportable 2 | #' @tags detritus-files 3 | #' @tags cluster 4 | 5 | library(future) 6 | 7 | message("*** Non-exportable globals ...") 8 | 9 | options(future.debug = FALSE) 10 | options(future.globals.onReference = "warning") 11 | plan(cluster, workers = 1L) 12 | 13 | 14 | message("* R connections ...") 15 | 16 | ## Create a dummy, global connection with a high enough connection index 17 | ## such that it won't conflict with an existing connection index on the 18 | ## worker. We use sink():s to "pad" with enough connections 19 | tmp_file <- tempfile() 20 | utils::capture.output(utils::capture.output({ 21 | con <- file(tmp_file, open = "wb") 22 | })) 23 | cat("hello\n", file = con) 24 | flush(con) 25 | bfr <- readLines(con = tmp_file) 26 | print(bfr) 27 | stopifnot(bfr == "hello") 28 | message(sprintf("Connection index of dummy 'con' connection: %d\n", as.integer(con))) 29 | stopifnot(as.integer(con) >= 6) 30 | 31 | 32 | message("- Run-time error") 33 | 34 | ## Assert we can detect the reference 35 | res <- tryCatch({ 36 | f <- future(cat("world\n", file = con), stdout = NA) 37 | }, FutureWarning = identity) 38 | print(res) 39 | stopifnot(inherits(res, "FutureWarning"), 40 | grepl("non-exportable reference", conditionMessage(res))) 41 | 42 | f <- future({ 43 | max <- max(getAllConnections(), na.rm = TRUE) 44 | cat(sprintf("Max connection index on worker: %d\n", max)) 45 | if (as.integer(con) <= max) { 46 | warning(sprintf("TEST ERROR: Index of global 'con' is the same of an existing connection of the worker: %d in [0,%d]", as.integer(con), max)) 47 | } 48 | cat("world\n", file = con) 49 | }) 50 | res <- tryCatch({ 51 | v <- value(f) 52 | }, error = identity) 53 | print(res) 54 | stopifnot(inherits(res, "error")) 55 | ## Nothing changed 56 | bfr <- readLines(con = tmp_file) 57 | print(bfr) 58 | stopifnot(bfr == "hello") 59 | 60 | close(con) 61 | file.remove(tmp_file) 62 | 63 | message("* R connections ... DONE") 64 | 65 | 66 | message("*** Non-exportable globals ... DONE") 67 | 68 | -------------------------------------------------------------------------------- /inst/testme/test-objectSize.R: -------------------------------------------------------------------------------- 1 | #' @tags globals objectSize 2 | 3 | library(future) 4 | 5 | objectSize <- future:::objectSize 6 | 7 | message("objectSize() ...") 8 | 9 | env <- new.env() 10 | env$a <- 3.14 11 | env$b <- 1:100 12 | 13 | env2 <- new.env() 14 | env2$env <- env 15 | 16 | ## Namespaces will be skipped 17 | env3 <- getNamespace("utils") 18 | 19 | fcn <- function(...) TRUE 20 | 21 | objs <- list( 22 | NULL, 23 | TRUE, 24 | 1L, 25 | 3.14, 26 | "hello", 27 | 1:100, 28 | 1:100 + 0.1, 29 | letters, 30 | list(a = 3.14, b = 1:100), 31 | list(a = 3.14, b = 1:100, c = list(a = 3.14, b = 1:100)), 32 | env, 33 | env2, 34 | env3, 35 | fcn, 36 | as.FutureGlobals(list(a = 3.14, b = 1:100)), 37 | list(x = as.FutureGlobals(list(a = 3.14, b = 1:100))), 38 | alist(a=) 39 | ) 40 | 41 | for (kk in seq_along(objs)) { 42 | obj <- objs[[kk]] 43 | message(sprintf("objectSize(<%s>) ...", mode(obj))) 44 | str(obj) 45 | 46 | size0 <- object.size(obj) 47 | str(size0) 48 | 49 | size <- objectSize(obj) 50 | str(size) 51 | 52 | message(sprintf("objectSize(<%s>) ... DONE", mode(obj))) 53 | } 54 | 55 | message("*** objectSize() - globals with non-trustful length() ...") 56 | 57 | length.CantTrustLength <- function(x) length(unclass(x)) + 1L 58 | 59 | .length <- future:::.length 60 | 61 | x <- structure(as.list(1:3), class = c("CantTrustLength", "list")) 62 | str(list(n = length(x), n_true = .length(x))) 63 | stopifnot(length(x) > .length(x)) 64 | size <- objectSize(x) 65 | print(size) 66 | 67 | message("*** objectSize() - globals with non-trustful length() ... DONE") 68 | 69 | message("objectSize() ... DONE") 70 | 71 | -------------------------------------------------------------------------------- /inst/testme/test-relaying,muffle.R: -------------------------------------------------------------------------------- 1 | #' @tags relaying 2 | #' @tags sequential 3 | 4 | library(future) 5 | 6 | options(future.debug = FALSE) 7 | 8 | message("*** withRestart() and muffling ...") 9 | 10 | ## https://github.com/futureverse/future/issues/485 11 | fcn <- function(...) { 12 | withRestarts({ 13 | cond <- simpleCondition("boom") 14 | class(cond) <- c("not_me", class(cond)) 15 | signalCondition(cond) 16 | "success" 17 | }, muffleSomething = function() { 18 | message("Condition muffled") 19 | "weird" 20 | }) 21 | } 22 | 23 | message(" - split = TRUE") 24 | ## Splitting output works 25 | f <- future(fcn(), split = TRUE) 26 | v <- value(f) 27 | message("RESULT: ", v) 28 | stopifnot(v == "success") 29 | 30 | message(" - muffleInclude = '^$'") 31 | f <- future(fcn(), conditions = structure("condition", muffleInclude = "^$")) 32 | v <- value(f) 33 | message("RESULT: ", v) 34 | stopifnot(v == "success") 35 | 36 | message(" - FIXME") 37 | ## FIXME: Ignoring specific condition class 'not_me' does not work 38 | f <- future(fcn(), conditions = structure("condition", exclude = "not_me")) 39 | v <- value(f) 40 | message("RESULT: ", v) 41 | if (isTRUE(as.logical(Sys.getenv("R_CHECK_IDEAL")))) { 42 | stopifnot(v == "success") 43 | } 44 | 45 | ## FIXME: Deprecate 'conditions = NULL' /HB 2025-02-16 46 | message(" - conditions = NULL (not recommended)") 47 | ## Disabling relaying conditions works 48 | f <- future(fcn(), conditions = NULL) 49 | v <- value(f) 50 | message("RESULT: ", v) 51 | stopifnot(v == "success") 52 | 53 | message("*** withRestart() and muffling ... DONE") 54 | 55 | -------------------------------------------------------------------------------- /inst/testme/test-relaying,split.R: -------------------------------------------------------------------------------- 1 | #' @tags relaying 2 | #' @tags sequential 3 | 4 | library(future) 5 | 6 | options(future.debug = FALSE) 7 | 8 | message("*** Relaying and split standard output and conditions ...") 9 | 10 | message(" - default (implicit split = FALSE)") 11 | 12 | plan(sequential) 13 | 14 | relay <- recordRelay({ 15 | f <- future({ 16 | cat("O\n") 17 | message("M") 18 | 1L 19 | }) 20 | }) 21 | message(" class: ", commaq(class(f))) 22 | stopifnot(length(relay$stdout) == 0L) 23 | stopifnot(length(relay$msgs) == 0L) 24 | relay <- recordRelay(v <- value(f)) 25 | stopifnot(identical(relay$stdout, "O\n")) 26 | stopifnot(identical(relay$msgs, "M\n")) 27 | 28 | 29 | message(" - split = FALSE") 30 | 31 | plan(sequential, split = FALSE) 32 | 33 | relay <- recordRelay({ 34 | f <- future({ 35 | cat("O\n") 36 | message("M") 37 | 1L 38 | }) 39 | }) 40 | message(" class: ", commaq(class(f))) 41 | stopifnot(length(relay$stdout) == 0L) 42 | stopifnot(length(relay$msgs) == 0L) 43 | relay <- recordRelay(v <- value(f)) 44 | stopifnot(identical(relay$stdout, "O\n")) 45 | stopifnot(identical(relay$msgs, "M\n")) 46 | 47 | 48 | message(" - split = TRUE") 49 | 50 | plan(sequential, split = TRUE) 51 | 52 | relay <- recordRelay({ 53 | f <- future({ 54 | cat("O\n") 55 | message("M") 56 | 1L 57 | }) 58 | }) 59 | message(" class: ", commaq(class(f))) 60 | stopifnot(identical(relay$stdout, "O\n")) 61 | stopifnot(identical(relay$msgs, "M\n")) 62 | relay <- recordRelay(v <- value(f)) 63 | stopifnot(identical(relay$stdout, "O\n")) 64 | stopifnot(identical(relay$msgs, "M\n")) 65 | 66 | 67 | message("*** Relaying and split standard output and conditions ... DONE") 68 | 69 | -------------------------------------------------------------------------------- /inst/testme/test-requestCore.R: -------------------------------------------------------------------------------- 1 | #' @tags requestCore 2 | #' @tags multicore 3 | 4 | library(future) 5 | 6 | message("*** requestCore() ...") 7 | 8 | message("*** requestCore() - exceptions ...") 9 | 10 | ## There are no cores to choose from 11 | res <- try(requestCore(function() {}, workers = 0), silent = TRUE) 12 | stopifnot(inherits(res, "try-error")) 13 | 14 | res <- try(requestCore(function() {}, timeout = -1.0), silent = TRUE) 15 | stopifnot(inherits(res, "try-error")) 16 | 17 | res <- try(requestCore(function() {}, alpha = 0.0), silent = TRUE) 18 | stopifnot(inherits(res, "try-error")) 19 | 20 | message("*** requestCore() - exceptions ... DONE") 21 | 22 | 23 | if (supportsMulticore()) { 24 | message("*** requestCore() - timeout ...") 25 | 26 | plan(multicore, workers = 2L) 27 | a %<-% { Sys.sleep(0.2); 1 } 28 | 29 | ## Fake single-worker multicore by using workers = 1L 30 | res <- try(requestCore(function() {}, workers = 1L, timeout = 0.5, delta = 0.1)) 31 | stopifnot(inherits(res, "try-error")) 32 | stopifnot(a == 1) 33 | 34 | message("*** requestCore() - timeout ... DONE") 35 | } 36 | 37 | message("*** requestCore() ... DONE") 38 | 39 | -------------------------------------------------------------------------------- /inst/testme/test-requestNode.R: -------------------------------------------------------------------------------- 1 | #' @tags requestNode 2 | #' @tags cluster 3 | #' @tags skip_on_cran 4 | 5 | library(future) 6 | 7 | message("*** requestNode() ...") 8 | 9 | message("*** requestNode() - exceptions ...") 10 | 11 | workers <- makeClusterPSOCK(2L) 12 | print(workers) 13 | 14 | res <- tryCatch({ 15 | requestNode(function() {}, workers = workers, timeout = -1.0) 16 | }, error = identity) 17 | stopifnot(inherits(res, "error")) 18 | 19 | res <- tryCatch({ 20 | requestNode(function() {}, workers = workers, alpha = 0) 21 | }, error = identity) 22 | stopifnot(inherits(res, "error")) 23 | 24 | parallel::stopCluster(workers) 25 | 26 | message("*** requestNode() - exceptions ... DONE") 27 | 28 | message("*** requestNode() - timeout ...") 29 | 30 | plan(cluster, workers = "localhost") 31 | f <- future({ Sys.sleep(0.2); 1 }) 32 | 33 | res <- tryCatch({ 34 | requestNode(function() { }, workers = f$workers, timeout = 0.5, delta = 0.1) 35 | }, error = identity) 36 | stopifnot(inherits(res, "error")) 37 | 38 | v <- value(f) 39 | print(v) 40 | stopifnot(v == 1L) 41 | 42 | plan(sequential) 43 | 44 | message("*** requestNode() - timeout ... DONE") 45 | 46 | message("*** requestNode() ... DONE") 47 | -------------------------------------------------------------------------------- /inst/testme/test-reserved-keyword-functions.R: -------------------------------------------------------------------------------- 1 | #' @tags globals reserved-keywords 2 | #' @tags sequential 3 | 4 | library(future) 5 | options(future.debug = FALSE) 6 | plan(sequential) 7 | 8 | message("Overriding reserved keyword functions ...") 9 | 10 | ## Identify globals used by the expanded future expression 11 | ...names <- globals::findGlobals(getExpression(future(NULL))) 12 | ...names <- ...names[sapply(...names, FUN = exists, mode = "function")] 13 | 14 | ## Skip test with '<-' because it causes issues for at least R 3.2.0 & 3.3.0 15 | if (getRversion() < "3.4.0") ...names <- setdiff(...names, "<-") 16 | 17 | print(...names) 18 | boom <- function(...) stop("Boom!") 19 | 20 | base_sprintf <- base::sprintf 21 | base_tryCatch <- base::tryCatch 22 | base_rm <- base::rm 23 | 24 | fails <- logical(length(...names)) 25 | names(fails) <- ...names 26 | for (kk in seq_along(...names)) { 27 | name <- ...names[kk] 28 | message(base_sprintf(" - %d/%d %s: ", kk, length(...names), sQuote(name)), appendLF = FALSE) 29 | assign(name, boom) 30 | res <- base_tryCatch(suppressWarnings({ 31 | future(NULL) 32 | }), error = identity) 33 | base_rm(list = name) 34 | if (inherits(res, "error")) { 35 | fails[kk] <- TRUE 36 | message("FAIL") 37 | } else { 38 | message("OK") 39 | } 40 | } 41 | 42 | message("Reserved keyword functions that must not be overridden:") 43 | print(names(fails)[fails]) 44 | 45 | ## future 1.15.1: 46 | ## [1] "{" "<-" "Sys.time" 47 | ## [4] "options" "requireNamespace" "if" 48 | ## [7] "packageVersion" "||" "!" 49 | ## [10] "<" "::" "is.na" 50 | ## [13] "rawConnection" "raw" "sink" 51 | ## [16] "on.exit" "is.null" "close" 52 | ## [19] "sys.nframe" "list" "tryCatch" 53 | ## [22] "$<-" "rawToChar" "rawConnectionValue" 54 | 55 | message("Overriding reserved keyword functions ... done") 56 | 57 | -------------------------------------------------------------------------------- /inst/testme/test-reset.R: -------------------------------------------------------------------------------- 1 | #' @tags reset 2 | #' @tags sequential multisession multicore 3 | 4 | library(future) 5 | options(future.debug = FALSE) 6 | 7 | ## Like mean(), but fails 90% of the time 8 | shaky_mean <- function(x) { 9 | if (as.double(Sys.time()) %% 1 < 0.90) stop("boom") 10 | mean(x) 11 | } 12 | 13 | x <- rnorm(100) 14 | 15 | 16 | message("*** reset() ...") 17 | for (strategy in supportedStrategies()) { 18 | message(sprintf("- plan('%s') ...", strategy)) 19 | plan(strategy) 20 | 21 | ## Calculate the mean of 'x' with a risk of failing randomly 22 | f <- future({ shaky_mean(x) }) 23 | 24 | ## Relaunch until success 25 | repeat({ 26 | v <- tryCatch(value(f), error = identity) 27 | if (!inherits(v, "error")) break 28 | message("Resetting failed future, and retry in 0.1 seconds") 29 | f <- reset(f) 30 | }) 31 | cat("mean:", v, "\n") 32 | 33 | } ## for (strategy ...) 34 | 35 | message("*** reset() ... DONE") 36 | 37 | -------------------------------------------------------------------------------- /inst/testme/test-sequential.R: -------------------------------------------------------------------------------- 1 | #' @tags sequential 2 | 3 | library(future) 4 | 5 | message("*** sequential() ...") 6 | 7 | message("- sequential() w/ required packages ...") 8 | 9 | f <- future(median(1:3), lazy = TRUE) 10 | print(f) 11 | 12 | ## Doesn't work if covr that depends on stats is loaded 13 | try(unloadNamespace("stats")) 14 | 15 | v <- value(f) 16 | print(v) 17 | stopifnot(identical(v, 2L)) 18 | 19 | stopifnot("stats" %in% loadedNamespaces()) 20 | 21 | message("- SequentialFuture() - 'local = FALSE' is defunct ...") 22 | 23 | res <- tryCatch({ 24 | f <- SequentialFuture(42, local = FALSE) 25 | }, error = identity) 26 | stopifnot(inherits(res, "error")) 27 | 28 | message("*** sequential() ... DONE") 29 | 30 | -------------------------------------------------------------------------------- /inst/testme/test-sessionDetails.R: -------------------------------------------------------------------------------- 1 | #' @tags sessionDetails 2 | 3 | library(future) 4 | 5 | sd <- sessionDetails() 6 | print(sd) 7 | print(sd, output = "message") 8 | 9 | rm(list = "sd") 10 | -------------------------------------------------------------------------------- /inst/testme/test-startup-onAttach.R: -------------------------------------------------------------------------------- 1 | #' @tags startup onAttach 2 | 3 | library(future) 4 | options(future.debug = FALSE) 5 | 6 | plan("default") 7 | 8 | message("*** .onAttach() ...") 9 | 10 | pkgname <- "future" 11 | 12 | message("- .onAttach() w/ option future.startup.loadScript ...") 13 | 14 | for (value in list(NULL, FALSE, TRUE)) { 15 | options(future.startup.loadScript = value) 16 | .onAttach(pkgname, pkgname) 17 | } 18 | 19 | message("- .onAttach() w/ option future.startup.loadScript ... DONE") 20 | 21 | message("- .onAttach() with ./.future.R ...") 22 | 23 | pathname <- ".future.R" 24 | xyz <- 0L 25 | cat("xyz <- 42L; cat('ping\n')\n", file = pathname) 26 | .onAttach(pkgname, pkgname) 27 | print(xyz) 28 | stopifnot(is.integer(xyz), xyz >= 0, xyz == 42L) 29 | file.remove(pathname) 30 | 31 | message("- .onAttach() with ./.future.R ... DONE") 32 | 33 | message("*** .onAttach() ... DONE") 34 | 35 | 36 | -------------------------------------------------------------------------------- /inst/testme/test-startup-parseCmdArgs.R: -------------------------------------------------------------------------------- 1 | #' @tags startup parseCmdArgs 2 | 3 | library(future) 4 | options(future.debug = FALSE) 5 | 6 | maxCores <- min(2L, availableCores(methods = "system")) 7 | 8 | plan("default") 9 | 10 | message("*** parseCmdArgs() ...") 11 | 12 | args <- parseCmdArgs() 13 | str(args) 14 | 15 | options(future.plan = NULL, future.cmdargs = c("-p", 1L)) 16 | args <- parseCmdArgs() 17 | str(args) 18 | stopifnot(args$p == 1L) 19 | 20 | options(future.plan = NULL, future.cmdargs = c(sprintf("--parallel=%d", maxCores))) 21 | args <- parseCmdArgs() 22 | str(args) 23 | stopifnot(args$p == maxCores) 24 | 25 | options(future.plan = NULL, future.cmdargs = c("-p", 1L, sprintf("--parallel=%d", maxCores))) 26 | args <- parseCmdArgs() 27 | str(args) 28 | stopifnot(args$p == maxCores) 29 | 30 | options(future.plan = NULL, future.cmdargs = c("-p", 0L)) 31 | args <- parseCmdArgs() 32 | stopifnot(is.null(args$p)) 33 | res <- tryCatch(parseCmdArgs(), warning = function(w) w) 34 | stopifnot(inherits(res, "warning")) 35 | 36 | options(future.plan = NULL, future.cmdargs = c("-p", .Machine$integer.max)) 37 | args <- parseCmdArgs() 38 | stopifnot(is.null(args$p)) 39 | res <- tryCatch(parseCmdArgs(), warning = function(w) w) 40 | stopifnot(inherits(res, "warning")) 41 | 42 | options(future.plan = NULL, future.cmdargs = NULL) 43 | 44 | message("*** parseCmdArgs() ... DONE") 45 | 46 | -------------------------------------------------------------------------------- /inst/testme/test-timeouts.R: -------------------------------------------------------------------------------- 1 | #' @tags timeouts 2 | #' @tags sequential multisession multicore 3 | 4 | library(future) 5 | options(future.debug = FALSE) 6 | 7 | ## Timeouts are only triggered after Sys.sleep() completes [1], 8 | ## so here we split up the sleep into multiple microsleeps 9 | sleep <- function(duration) { 10 | until <- Sys.time() + duration 11 | while (Sys.time() < until) { 12 | Sys.sleep(0.01) 13 | } 14 | } 15 | 16 | strategies <- supportedStrategies() 17 | strategies <- setdiff(strategies, "sequential") 18 | for (strategy in strategies) { 19 | message(sprintf("plan('%s') ...", strategy)) 20 | plan(strategy) 21 | 22 | n0 <- nbrOfFreeWorkers() 23 | message("Number of free workers: ", n0) 24 | 25 | message("Create a future that times out after 0.2 seconds into the evaluation") 26 | f <- future({ 27 | setTimeLimit(elapsed = 0.2, transient = TRUE) 28 | sleep(1.0) 29 | 42 30 | }) 31 | 32 | n <- nbrOfFreeWorkers() 33 | message("Number of free workers (after interupt): ", n) 34 | 35 | message("Resolve future") 36 | f <- resolve(f) 37 | stopifnot(resolved(f)) 38 | n <- nbrOfFreeWorkers() 39 | message("Number of free workers (after resolve): ", n) 40 | 41 | message("Get future results") 42 | r <- result(f) 43 | stopifnot(inherits(r, "FutureResult")) 44 | n <- nbrOfFreeWorkers() 45 | message("Number of free workers (after result): ", n) 46 | stopifnot(n == n0) 47 | 48 | message("Get the value, which triggers relay of timeout error") 49 | v <- tryCatch(value(f), error = identity) 50 | print(v) 51 | stopifnot(inherits(v, "error")) 52 | 53 | message("Create another future") 54 | f <- future(42) 55 | v <- value(f) 56 | n <- nbrOfFreeWorkers() 57 | message("Number of free workers (after result): ", n) 58 | stopifnot(n == n0) 59 | 60 | message(sprintf("plan('%s') .. done", strategy)) 61 | } 62 | 63 | -------------------------------------------------------------------------------- /inst/testme/test-uuid.R: -------------------------------------------------------------------------------- 1 | #' @tags utils-internal session_uuid 2 | 3 | library(future) 4 | session_uuid <- future:::session_uuid 5 | 6 | message("*** session_uuid() ...") 7 | 8 | id0 <- session_uuid() 9 | print(id0) 10 | 11 | ## Reset session UUID (hack) 12 | environment(session_uuid)$uuids <- list() 13 | 14 | id <- session_uuid() 15 | print(id) 16 | stopifnot(id != id0) 17 | 18 | ## Assert that forked child processes get a unique session id 19 | ## Issue: https://github.com/futureverse/future/issues/187 20 | if (supportsMulticore()) { 21 | plan(multicore, workers = 2L) 22 | fs <- lapply(1:2, FUN = function(i) { 23 | future({ 24 | session_uuid() 25 | }) 26 | }) 27 | ids <- unlist(value(fs)) 28 | print(ids) 29 | stopifnot(all(ids != id), length(unique(ids)) == 2L) 30 | } 31 | 32 | message("*** session_uuid() ... DONE") 33 | 34 | -------------------------------------------------------------------------------- /inst/testme/test-value-error-cancels-set.R: -------------------------------------------------------------------------------- 1 | #' @tags interrupt 2 | #' @tags detritus-files 3 | #' @tags detritus-connections 4 | #' @tags multisession multicore 5 | 6 | library(future) 7 | options(future.debug = FALSE) 8 | 9 | strategies <- supportedStrategies() 10 | strategies <- setdiff(strategies, "sequential") 11 | 12 | for (strategy in strategies) { 13 | message(sprintf("plan('%s') ...", strategy)) 14 | plan(strategy) 15 | 16 | n0 <- nbrOfFreeWorkers() 17 | message("Number of free workers: ", n0) 18 | 19 | message("Create four futures, where one produces an error") 20 | fs <- lapply(c(4, 1, 2, 3), function(x) future({ 21 | Sys.sleep(x/4) 22 | if (x == 1) stop("boom") 23 | x 24 | })) 25 | 26 | rs <- resolved(fs) 27 | print(rs) 28 | 29 | message("Assert there is an error") 30 | vs <- tryCatch(value(fs), error = identity) 31 | 32 | ## Assert that value() returned the 'boom' error, and not 33 | ## a FutureError, e.g. FutureInterruptError 34 | print(vs) 35 | stopifnot( 36 | inherits(vs, "error"), 37 | !inherits(vs, "FutureError"), 38 | conditionMessage(vs) == "boom" 39 | ) 40 | 41 | ## Assert that value(fs) resolves all futures before returning, 42 | ## regardless of the backend supporting interrupting futures or not. 43 | message("Assert that all futures are resolved by value()") 44 | rs <- resolved(fs) 45 | print(rs) 46 | stopifnot(all(rs)) 47 | 48 | message(sprintf("plan('%s') .. done", strategy)) 49 | } 50 | 51 | message("Shut down future backend") 52 | plan(sequential) 53 | gc() 54 | -------------------------------------------------------------------------------- /inst/vignettes-static/incl/future-1-overview-example2.R: -------------------------------------------------------------------------------- 1 | pid <- Sys.getpid() 2 | pid 3 | a %<-% { 4 | pid <- Sys.getpid() 5 | cat("Future 'a' ...\n") 6 | 3.14 7 | } 8 | b %<-% { 9 | rm(pid) ## no effect on global 'pid' 10 | cat("Future 'b' ...\n") 11 | Sys.getpid() 12 | } 13 | c %<-% { 14 | cat("Future 'c' ...\n") 15 | 2 * a 16 | } 17 | b 18 | c 19 | a 20 | pid 21 | -------------------------------------------------------------------------------- /inst/vignettes-static/incl/future-1-overview-example3.R: -------------------------------------------------------------------------------- 1 | pid <- Sys.getpid() 2 | 3 | a %<-% { 4 | cat("Future 'a' ...\n") 5 | Sys.getpid() 6 | } 7 | 8 | b %<-% { 9 | cat("Future 'b' ...\n") 10 | b1 %<-% { 11 | cat("Future 'b1' ...\n") 12 | Sys.getpid() 13 | } 14 | b2 %<-% { 15 | cat("Future 'b2' ...\n") 16 | Sys.getpid() 17 | } 18 | c(b.pid = Sys.getpid(), b1.pid = b1, b2.pid = b2) 19 | } 20 | -------------------------------------------------------------------------------- /man/FutureGlobals.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/protected_api-FutureGlobals-class.R 3 | \name{FutureGlobals} 4 | \alias{FutureGlobals} 5 | \alias{as.FutureGlobals} 6 | \alias{as.FutureGlobals.FutureGlobals} 7 | \alias{as.FutureGlobals.Globals} 8 | \alias{as.FutureGlobals.list} 9 | \alias{[.FutureGlobals} 10 | \alias{c.FutureGlobals} 11 | \alias{unique.FutureGlobals} 12 | \title{A representation of a set of globals used with futures} 13 | \usage{ 14 | FutureGlobals(object = list(), resolved = FALSE, total_size = NA_real_, ...) 15 | } 16 | \arguments{ 17 | \item{object}{A named list.} 18 | 19 | \item{resolved}{A logical indicating whether these globals 20 | have been scanned for and resolved futures or not.} 21 | 22 | \item{total_size}{The total size of all globals, if known.} 23 | 24 | \item{\ldots}{Not used.} 25 | } 26 | \value{ 27 | An object of class \code{FutureGlobals}. 28 | } 29 | \description{ 30 | A representation of a set of globals used with futures 31 | } 32 | \details{ 33 | This class extends the \link[globals]{Globals} class by adding 34 | attributes \code{resolved} and \code{total_size}. 35 | } 36 | \keyword{internal} 37 | -------------------------------------------------------------------------------- /man/FutureResult.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/protected_api-FutureResult-class.R 3 | \name{FutureResult} 4 | \alias{FutureResult} 5 | \alias{as.character.FutureResult} 6 | \alias{print.FutureResult} 7 | \title{Results from resolving a future} 8 | \usage{ 9 | FutureResult( 10 | value = NULL, 11 | visible = TRUE, 12 | stdout = NULL, 13 | conditions = NULL, 14 | rng = FALSE, 15 | ..., 16 | uuid = NULL, 17 | started = .POSIXct(NA_real_), 18 | finished = Sys.time(), 19 | version = "1.8" 20 | ) 21 | 22 | \method{as.character}{FutureResult}(x, ...) 23 | 24 | \method{print}{FutureResult}(x, ...) 25 | } 26 | \arguments{ 27 | \item{value}{The value of the future expression. 28 | If the expression was not fully resolved (e.g. an error) occurred, 29 | the the value is \code{NULL}.} 30 | 31 | \item{visible}{If TRUE, the value was visible, otherwise invisible.} 32 | 33 | \item{conditions}{A list of zero or more list elements each containing 34 | a captured \link[base:conditions]{condition} and possibly more meta data such as the 35 | call stack and a timestamp.} 36 | 37 | \item{rng}{If TRUE, the \code{.Random.seed} was updated from resolving the 38 | future, otherwise not.} 39 | 40 | \item{started, finished}{\link[base:DateTimeClasses]{POSIXct} timestamps 41 | when the evaluation of the future expression was started and finished.} 42 | 43 | \item{version}{The version format of the results.} 44 | 45 | \item{\ldots}{(optional) Additional named results to be returned.} 46 | } 47 | \value{ 48 | An object of class FutureResult. 49 | } 50 | \description{ 51 | Results from resolving a future 52 | } 53 | \details{ 54 | This function is only part of the \emph{backend} Future API. 55 | This function is \emph{not} part of the frontend Future API. 56 | } 57 | \section{Note to developers}{ 58 | 59 | The FutureResult structure is \emph{under development} and may change at anytime, 60 | e.g. elements may be renamed or removed. Because of this, please avoid 61 | accessing the elements directly in code. Feel free to reach out if you need 62 | to do so in your code. 63 | } 64 | 65 | \keyword{internal} 66 | -------------------------------------------------------------------------------- /man/MulticoreFuture-class.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/backend_api-11.MulticoreFutureBackend-class.R 3 | \name{MulticoreFuture-class} 4 | \alias{MulticoreFuture-class} 5 | \alias{resolved.MulticoreFuture} 6 | \title{A multicore future is a future whose value will be resolved asynchronously in a parallel process} 7 | \usage{ 8 | \method{resolved}{MulticoreFuture}(x, run = TRUE, timeout = NULL, ...) 9 | } 10 | \value{ 11 | \code{MulticoreFuture()} returns an object of class \code{MulticoreFuture}. 12 | } 13 | \description{ 14 | A multicore future is a future whose value will be resolved asynchronously in a parallel process 15 | } 16 | \section{Usage}{ 17 | 18 | To use 'multicore' futures, use \code{plan(multicore, ...)}, cf. \link{multicore}. 19 | } 20 | 21 | \keyword{internal} 22 | -------------------------------------------------------------------------------- /man/MultiprocessFuture-class.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in 3 | % R/backend_api-03.MultiprocessFutureBackend-class.R 4 | \name{MultiprocessFuture-class} 5 | \alias{MultiprocessFuture-class} 6 | \alias{MultiprocessFuture} 7 | \title{A multiprocess future is a future whose value will be resolved asynchronously in a parallel process} 8 | \usage{ 9 | MultiprocessFuture(expr = NULL, substitute = TRUE, envir = parent.frame(), ...) 10 | } 11 | \arguments{ 12 | \item{expr}{An \R \link[base]{expression}.} 13 | 14 | \item{substitute}{If TRUE, argument \code{expr} is 15 | \code{\link[base]{substitute}()}:ed, otherwise not.} 16 | 17 | \item{envir}{The \link{environment} from where global objects should be 18 | identified.} 19 | 20 | \item{\ldots}{Additional named elements passed to \code{\link[=Future]{Future()}}.} 21 | } 22 | \value{ 23 | \code{MultiprocessFuture()} returns an object of class \code{MultiprocessFuture}. 24 | } 25 | \description{ 26 | A multiprocess future is a future whose value will be resolved asynchronously in a parallel process 27 | } 28 | \keyword{internal} 29 | -------------------------------------------------------------------------------- /man/UniprocessFuture-class.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/backend_api-UniprocessFuture-class.R 3 | \name{UniprocessFuture-class} 4 | \alias{UniprocessFuture-class} 5 | \alias{UniprocessFuture} 6 | \title{An uniprocess future is a future whose value will be resolved synchronously in the current process} 7 | \usage{ 8 | UniprocessFuture(expr = NULL, substitute = TRUE, envir = parent.frame(), ...) 9 | } 10 | \arguments{ 11 | \item{expr}{An \R \link[base]{expression}.} 12 | 13 | \item{substitute}{If TRUE, argument \code{expr} is 14 | \code{\link[base]{substitute}()}:ed, otherwise not.} 15 | 16 | \item{envir}{The \link{environment} from where global objects should be 17 | identified.} 18 | 19 | \item{\ldots}{Additional named elements passed to \code{\link[=Future]{Future()}}.} 20 | } 21 | \value{ 22 | \code{UniprocessFuture()} returns an object of class \code{UniprocessFuture}. 23 | } 24 | \description{ 25 | An uniprocess future is a future whose value will be resolved synchronously in the current process 26 | } 27 | \keyword{internal} 28 | -------------------------------------------------------------------------------- /man/backtrace.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils_api-backtrace.R 3 | \name{backtrace} 4 | \alias{backtrace} 5 | \title{Back trace the expressions evaluated when an error was caught} 6 | \usage{ 7 | backtrace(future, envir = parent.frame(), ...) 8 | } 9 | \arguments{ 10 | \item{future}{A future with a caught error.} 11 | 12 | \item{envir}{the environment where to locate the future.} 13 | 14 | \item{\ldots}{Not used.} 15 | } 16 | \value{ 17 | A list with the future's call stack that led up to the error. 18 | } 19 | \description{ 20 | Back trace the expressions evaluated when an error was caught 21 | } 22 | \examples{ 23 | my_log <- function(x) log(x) 24 | foo <- function(...) my_log(...) 25 | 26 | f <- future({ foo("a") }) 27 | res <- tryCatch({ 28 | v <- value(f) 29 | }, error = function(ex) { 30 | t <- backtrace(f) 31 | print(t) 32 | }) 33 | \dontshow{ 34 | ## R CMD check: make sure any open connections are closed afterward 35 | plan(sequential) 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /man/cancel.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/core_api-cancel.R 3 | \name{cancel} 4 | \alias{cancel} 5 | \title{Cancel a future} 6 | \usage{ 7 | cancel(x, interrupt = TRUE, ...) 8 | } 9 | \arguments{ 10 | \item{x}{A Future.} 11 | 12 | \item{interrupt}{If TRUE, running futures are interrupted, if the 13 | future backend supports it.} 14 | 15 | \item{\ldots}{All arguments used by the S3 methods.} 16 | } 17 | \value{ 18 | \code{cancel()} returns (invisibly) the canceled \link{Future}s after 19 | flagging them as "canceled" and possibly interrupting them as well. 20 | 21 | Canceling a lazy or a finished future has no effect. 22 | } 23 | \description{ 24 | Cancels futures, with the option to interrupt running ones. 25 | } 26 | \examples{ 27 | \dontshow{if ((interactive() || .Platform[["OS.type"]] != "windows")) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 28 | ## Set up two parallel workers 29 | plan(multisession, workers = 2) 30 | 31 | ## Launch two long running future 32 | fs <- lapply(c(1, 2), function(duration) { 33 | future({ 34 | Sys.sleep(duration) 35 | 42 36 | }) 37 | }) 38 | 39 | ## Wait until at least one of the futures is resolved 40 | while (!any(resolved(fs))) Sys.sleep(0.1) 41 | 42 | ## Cancel the future that is not yet resolved 43 | r <- resolved(fs) 44 | cancel(fs[!r]) 45 | 46 | ## Get the value of the resolved future 47 | f <- fs[r] 48 | v <- value(f) 49 | message("Result: ", v) 50 | 51 | ## The value of the canceled future is an error 52 | try(v <- value(fs[!r])) 53 | 54 | ## Shut down parallel workers 55 | plan(sequential) 56 | \dontshow{\}) # examplesIf} 57 | } 58 | \seealso{ 59 | A canceled future can be \code{\link[=reset]{reset()}} to a lazy, vanilla future 60 | such that it can be relaunched, possible on another future backend. 61 | } 62 | -------------------------------------------------------------------------------- /man/clusterExportSticky.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-sticky_globals.R 3 | \name{clusterExportSticky} 4 | \alias{clusterExportSticky} 5 | \title{Export globals to the sticky-globals environment of the cluster nodes} 6 | \usage{ 7 | clusterExportSticky(cl, globals) 8 | } 9 | \arguments{ 10 | \item{cl}{(cluster) A cluster object as returned by 11 | \code{\link[parallel:makeCluster]{parallel::makeCluster()}}.} 12 | 13 | \item{globals}{(list) A named list of sticky globals to be exported.} 14 | } 15 | \value{ 16 | (invisible; cluster) The cluster object. 17 | } 18 | \description{ 19 | Export globals to the sticky-globals environment of the cluster nodes 20 | } 21 | \details{ 22 | This requires that the \pkg{future} package is installed on the cluster 23 | nodes. 24 | } 25 | \keyword{internal} 26 | -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futureverse/future/83f2c3ecaf572daba957c07356d55e2cb2c955b6/man/figures/logo.png -------------------------------------------------------------------------------- /man/find_references.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-marshalling.R 3 | \name{find_references} 4 | \alias{find_references} 5 | \alias{assert_no_references} 6 | \title{Get the first or all references of an \R object} 7 | \usage{ 8 | find_references(x, first_only = FALSE) 9 | 10 | assert_no_references( 11 | x, 12 | action = c("error", "warning", "message", "string"), 13 | source = c("globals", "value") 14 | ) 15 | } 16 | \arguments{ 17 | \item{x}{The \R object to be checked.} 18 | 19 | \item{first_only}{If \code{TRUE}, only the first reference is returned, 20 | otherwise all references.} 21 | 22 | \item{action}{Type of action to take if a reference is found.} 23 | 24 | \item{source}{Is the source of \code{x} the globals or the value of the future?} 25 | } 26 | \value{ 27 | \code{find_references()} returns a list of zero or more references 28 | identified. 29 | 30 | If a reference is detected, an informative error, warning, message, 31 | or a character string is produced, otherwise \code{NULL} is returned 32 | invisibly. 33 | } 34 | \description{ 35 | Get the first or all references of an \R object 36 | 37 | Assert that there are no references among the identified globals 38 | } 39 | \keyword{internal} 40 | -------------------------------------------------------------------------------- /man/futureOf.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/delayed_api-futureOf.R 3 | \name{futureOf} 4 | \alias{futureOf} 5 | \title{Get the future of a future variable} 6 | \usage{ 7 | futureOf( 8 | var = NULL, 9 | envir = parent.frame(), 10 | mustExist = TRUE, 11 | default = NA, 12 | drop = FALSE 13 | ) 14 | } 15 | \arguments{ 16 | \item{var}{the variable. If NULL, all futures in the 17 | environment are returned.} 18 | 19 | \item{envir}{the environment where to search from.} 20 | 21 | \item{mustExist}{If TRUE and the variable does not exists, then 22 | an informative error is thrown, otherwise NA is returned.} 23 | 24 | \item{default}{the default value if future was not found.} 25 | 26 | \item{drop}{if TRUE and \code{var} is NULL, then returned list 27 | only contains futures, otherwise also \code{default} values.} 28 | } 29 | \value{ 30 | A \link{Future} (or \code{default}). 31 | If \code{var} is NULL, then a named list of Future:s are returned. 32 | } 33 | \description{ 34 | Get the future of a future variable that has been created directly 35 | or indirectly via \code{\link[=future]{future()}}. 36 | } 37 | \examples{ 38 | a \%<-\% { 1 } 39 | 40 | f <- futureOf(a) 41 | print(f) 42 | 43 | b \%<-\% { 2 } 44 | 45 | f <- futureOf(b) 46 | print(f) 47 | 48 | ## All futures 49 | fs <- futureOf() 50 | print(fs) 51 | 52 | 53 | ## Futures part of environment 54 | env <- new.env() 55 | env$c \%<-\% { 3 } 56 | 57 | f <- futureOf(env$c) 58 | print(f) 59 | 60 | f2 <- futureOf(c, envir = env) 61 | print(f2) 62 | 63 | f3 <- futureOf("c", envir = env) 64 | print(f3) 65 | 66 | fs <- futureOf(envir = env) 67 | print(fs) 68 | } 69 | -------------------------------------------------------------------------------- /man/futureSessionInfo.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils_api-futureSessionInfo.R 3 | \name{futureSessionInfo} 4 | \alias{futureSessionInfo} 5 | \title{Get future-specific session information and validate current backend} 6 | \usage{ 7 | futureSessionInfo(test = TRUE, anonymize = TRUE) 8 | } 9 | \arguments{ 10 | \item{test}{If TRUE, one or more futures are created to query workers 11 | and validate their information.} 12 | 13 | \item{anonymize}{If TRUE, user names and host names are anonymized.} 14 | } 15 | \value{ 16 | Nothing. 17 | } 18 | \description{ 19 | Get future-specific session information and validate current backend 20 | } 21 | \examples{ 22 | plan(multisession, workers = 2) 23 | futureSessionInfo() 24 | plan(sequential) 25 | } 26 | -------------------------------------------------------------------------------- /man/futures.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/protected_api-futures.R 3 | \name{futures} 4 | \alias{futures} 5 | \title{Get all futures in a container} 6 | \usage{ 7 | futures(x, ...) 8 | } 9 | \arguments{ 10 | \item{x}{An environment, a list, or a list environment.} 11 | 12 | \item{\ldots}{Not used.} 13 | } 14 | \value{ 15 | An object of same type as \code{x} and with the same names 16 | and/or dimensions, if set. 17 | } 18 | \description{ 19 | Gets all futures in an environment, a list, or a list environment 20 | and returns an object of the same class (and dimensions). 21 | Non-future elements are returned as is. 22 | } 23 | \details{ 24 | This function is useful for retrieve futures that were created via 25 | future assignments (\verb{\%<-\%}) and therefore stored as promises. 26 | This function turns such promises into standard \code{Future} 27 | objects. 28 | } 29 | -------------------------------------------------------------------------------- /man/getExpression.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/backend_api-Future-class.R 3 | \name{getExpression} 4 | \alias{getExpression} 5 | \alias{getExpression.Future} 6 | \title{Inject code for the next type of future to use for nested futures} 7 | \usage{ 8 | getExpression(future, ...) 9 | } 10 | \arguments{ 11 | \item{future}{Current future.} 12 | 13 | \item{\ldots}{Not used.} 14 | } 15 | \value{ 16 | A future expression with code injected to set what 17 | type of future to use for nested futures, iff any. 18 | } 19 | \description{ 20 | Inject code for the next type of future to use for nested futures 21 | } 22 | \details{ 23 | If there is no future backend specified after this one, the default 24 | is to use \link{sequential} futures. This conservative approach protects 25 | against spawning off recursive futures by mistake, especially 26 | \link{multicore} and \link{multisession} ones. 27 | The default will also set \code{options(mc.cores = 1L)} (*) so that 28 | no parallel \R processes are spawned off by functions such as 29 | \code{parallel::mclapply()} and friends. 30 | 31 | Currently it is not possible to specify what type of nested 32 | futures to be used, meaning the above default will always be 33 | used. 34 | See \href{https://github.com/futureverse/future/issues/37}{Issue #37} 35 | for plans on adding support for custom nested future types. 36 | 37 | (*) Ideally we would set \code{mc.cores = 0} but that will unfortunately 38 | cause \code{mclapply()} and friends to generate an error saying 39 | "'mc.cores' must be >= 1". Ideally those functions should 40 | fall back to using the non-multicore alternative in this 41 | case, e.g. \code{mclapply(...)} => \code{lapply(...)}. 42 | See \url{https://github.com/HenrikBengtsson/Wishlist-for-R/issues/7} 43 | for a discussion on this. 44 | } 45 | \keyword{internal} 46 | -------------------------------------------------------------------------------- /man/mandelbrot.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/demo_api-mandelbrot.R 3 | \name{mandelbrot} 4 | \alias{mandelbrot} 5 | \alias{as.raster.Mandelbrot} 6 | \alias{plot.Mandelbrot} 7 | \alias{mandelbrot_tiles} 8 | \alias{mandelbrot.matrix} 9 | \alias{mandelbrot.numeric} 10 | \title{Mandelbrot convergence counts} 11 | \usage{ 12 | mandelbrot(...) 13 | 14 | \method{mandelbrot}{matrix}(Z, maxIter = 200L, tau = 2, ...) 15 | 16 | \method{mandelbrot}{numeric}( 17 | xmid = -0.75, 18 | ymid = 0, 19 | side = 3, 20 | resolution = 400L, 21 | maxIter = 200L, 22 | tau = 2, 23 | ... 24 | ) 25 | } 26 | \arguments{ 27 | \item{Z}{A complex matrix for which convergence 28 | counts should be calculated.} 29 | 30 | \item{maxIter}{Maximum number of iterations per bin.} 31 | 32 | \item{tau}{A threshold; the radius when calling 33 | divergence (Mod(z) > tau).} 34 | 35 | \item{xmid, ymid, side, resolution}{Alternative specification of 36 | the complex plane \code{Z}, where 37 | \code{mean(Re(Z)) == xmid}, 38 | \code{mean(Im(Z)) == ymid}, 39 | \code{diff(range(Re(Z))) == side}, 40 | \code{diff(range(Im(Z))) == side}, and 41 | \code{dim(Z) == c(resolution, resolution)}.} 42 | } 43 | \value{ 44 | Returns an integer matrix (of class Mandelbrot) with 45 | non-negative counts. 46 | } 47 | \description{ 48 | Mandelbrot convergence counts 49 | } 50 | \examples{ 51 | counts <- mandelbrot(xmid = -0.75, ymid = 0, side = 3) 52 | str(counts) 53 | \dontrun{ 54 | plot(counts) 55 | } 56 | 57 | \dontrun{ 58 | demo("mandelbrot", package = "future", ask = FALSE) 59 | } 60 | 61 | } 62 | \author{ 63 | The internal Mandelbrot algorithm was inspired by and 64 | adopted from similar GPL code of Martin Maechler available 65 | from ftp://stat.ethz.ch/U/maechler/R/ on 2005-02-18 (sic!). 66 | } 67 | \keyword{internal} 68 | -------------------------------------------------------------------------------- /man/nbrOfWorkers.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils_api-nbrOfWorkers.R 3 | \name{nbrOfWorkers} 4 | \alias{nbrOfWorkers} 5 | \alias{nbrOfFreeWorkers} 6 | \title{Get the number of workers available} 7 | \usage{ 8 | nbrOfWorkers(evaluator = NULL) 9 | 10 | nbrOfFreeWorkers(evaluator = NULL, background = FALSE, ...) 11 | } 12 | \arguments{ 13 | \item{evaluator}{A future evaluator function. 14 | If NULL (default), the current evaluator as returned 15 | by \code{\link[=plan]{plan()}} is used.} 16 | 17 | \item{background}{If TRUE, only workers that can process a future in the 18 | background are considered. If FALSE, also workers running in the main \R 19 | process are considered, e.g. when using the 'sequential' backend.} 20 | 21 | \item{\ldots}{Not used; reserved for future use.} 22 | } 23 | \value{ 24 | \code{nbrOfWorkers()} returns a positive number in \eqn{{1, 2, 3, ...}}, which 25 | for some future backends may also be \code{+Inf}. 26 | 27 | \code{nbrOfFreeWorkers()} returns a non-negative number in 28 | \eqn{{0, 1, 2, 3, ...}} which is less than or equal to \code{nbrOfWorkers()}. 29 | } 30 | \description{ 31 | Get the number of workers available 32 | } 33 | \examples{ 34 | plan(multisession) 35 | nbrOfWorkers() ## == availableCores() 36 | 37 | plan(sequential) 38 | nbrOfWorkers() ## == 1 39 | } 40 | -------------------------------------------------------------------------------- /man/nullcon.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-basic.R 3 | \name{nullcon} 4 | \alias{nullcon} 5 | \title{Creates a connection to the system null device} 6 | \usage{ 7 | nullcon() 8 | } 9 | \value{ 10 | Returns a open, binary \code{\link[base:connections]{base::connection()}}. 11 | } 12 | \description{ 13 | Creates a connection to the system null device 14 | } 15 | \keyword{internal} 16 | -------------------------------------------------------------------------------- /man/private_length.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-basic.R 3 | \name{.length} 4 | \alias{.length} 5 | \title{Gets the length of an object without dispatching} 6 | \usage{ 7 | .length(x) 8 | } 9 | \arguments{ 10 | \item{x}{Any \R object.} 11 | } 12 | \value{ 13 | A non-negative integer. 14 | } 15 | \description{ 16 | Gets the length of an object without dispatching 17 | } 18 | \details{ 19 | This function returns \code{length(unclass(x))}, but tries to avoid 20 | calling \code{unclass(x)} unless necessary. 21 | } 22 | \seealso{ 23 | \code{\link{.subset}()} and \code{\link{.subset2}()}. 24 | } 25 | \keyword{internal} 26 | -------------------------------------------------------------------------------- /man/re-exports.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/000.re-exports.R 3 | \name{re-exports} 4 | \alias{re-exports} 5 | \alias{as.cluster} 6 | \alias{availableCores} 7 | \alias{availableWorkers} 8 | \alias{makeClusterPSOCK} 9 | \alias{supportsMulticore} 10 | \title{Functions Moved to 'parallelly'} 11 | \description{ 12 | The following function used to be part of \pkg{future} but has since 13 | been migrated to \pkg{parallelly}. The migration started with 14 | \pkg{future} 1.20.0 (November 2020). They were moved because they 15 | are also useful outside of the \pkg{future} framework. 16 | } 17 | \details{ 18 | \emph{If you are using any of these from the \pkg{future} package, please 19 | switch to use the ones from the \pkg{parallelly} package. Thank you!} 20 | \itemize{ 21 | \item \code{\link[parallelly:as.cluster]{parallelly::as.cluster()}} 22 | \item \code{\link[parallelly:autoStopCluster]{parallelly::autoStopCluster()}} (no longer re-exported) 23 | \item \code{\link[parallelly:availableCores]{parallelly::availableCores()}} 24 | \item \code{\link[parallelly:availableWorkers]{parallelly::availableWorkers()}} 25 | \item \code{\link[parallelly:makeClusterMPI]{parallelly::makeClusterMPI()}} (no longer re-exported) 26 | \item \code{\link[parallelly:makeClusterPSOCK]{parallelly::makeClusterPSOCK()}} 27 | \item \code{\link[parallelly:makeClusterPSOCK]{parallelly::makeNodePSOCK()}} (no longer re-exported) 28 | \item \code{\link[parallelly:supportsMulticore]{parallelly::supportsMulticore()}} 29 | } 30 | 31 | For backward-compatible reasons, \emph{some} of these functions remain 32 | available as exact copies also from this package (as re-exports), e.g. 33 | 34 | \if{html}{\out{
}}\preformatted{cl <- parallelly::makeClusterPSOCK(2) 35 | }\if{html}{\out{
}} 36 | 37 | can still be accessed as: 38 | 39 | \if{html}{\out{
}}\preformatted{cl <- future::makeClusterPSOCK(2) 40 | }\if{html}{\out{
}} 41 | 42 | \emph{Note that it is the goal to remove all of the above from this package.} 43 | } 44 | \keyword{internal} 45 | -------------------------------------------------------------------------------- /man/readImmediateConditions.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-immediateCondition.R 3 | \name{readImmediateConditions} 4 | \alias{readImmediateConditions} 5 | \alias{saveImmediateCondition} 6 | \title{Writes and Reads 'immediateCondition' RDS Files} 7 | \usage{ 8 | readImmediateConditions( 9 | path = immediateConditionsPath(rootPath = rootPath), 10 | rootPath = tempdir(), 11 | pattern = "[.]rds$", 12 | include = getOption("future.relay.immediate", "immediateCondition"), 13 | signal = FALSE, 14 | remove = TRUE 15 | ) 16 | 17 | saveImmediateCondition( 18 | cond, 19 | path = immediateConditionsPath(rootPath = rootPath), 20 | rootPath = tempdir() 21 | ) 22 | } 23 | \arguments{ 24 | \item{path}{(character string) The folder where the RDS files are.} 25 | 26 | \item{pattern}{(character string) A regular expression selecting 27 | the RDS files to be read.} 28 | 29 | \item{include}{(character vector) The class or classes of the objects 30 | to be kept.} 31 | 32 | \item{signal}{(logical) If TRUE, the condition read are signaled.} 33 | 34 | \item{remove}{(logical) If TRUE, the RDS files used are removed on exit.} 35 | 36 | \item{cond}{A condition of class \code{immediateCondition}.} 37 | } 38 | \value{ 39 | \code{readImmediateConditions()} returns an unnamed \link[base:list]{base::list} of 40 | named lists with elements \code{condition} and \code{signaled}, where 41 | the \code{condition} elements hold \code{immediateCondition} objects. 42 | 43 | \code{saveImmediateCondition()} returns, invisibly, the pathname of 44 | the RDS written. 45 | } 46 | \description{ 47 | Writes and Reads 'immediateCondition' RDS Files 48 | } 49 | \keyword{internal} 50 | -------------------------------------------------------------------------------- /man/requestCore.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/backend_api-11.MulticoreFutureBackend-class.R 3 | \name{requestCore} 4 | \alias{requestCore} 5 | \title{Request a core for multicore processing} 6 | \usage{ 7 | requestCore( 8 | await, 9 | workers = availableCores(constraints = "multicore"), 10 | timeout, 11 | delta, 12 | alpha 13 | ) 14 | } 15 | \arguments{ 16 | \item{await}{A function used to try to "collect" 17 | finished multicore subprocesses.} 18 | 19 | \item{workers}{Total number of workers available.} 20 | 21 | \item{timeout}{Maximum waiting time (in seconds) allowed 22 | before a timeout error is generated.} 23 | 24 | \item{delta}{Then base interval (in seconds) to wait 25 | between each try.} 26 | 27 | \item{alpha}{A multiplicative factor used to increase 28 | the wait interval after each try.} 29 | } 30 | \value{ 31 | Invisible TRUE. If no cores are available after 32 | extensive waiting, then a timeout error is thrown. 33 | } 34 | \description{ 35 | If no cores are available, the current process 36 | blocks until a core is available. 37 | } 38 | \keyword{internal} 39 | -------------------------------------------------------------------------------- /man/reset.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/core_api-reset.R 3 | \name{reset} 4 | \alias{reset} 5 | \title{Reset a finished, failed, canceled, or interrupted future to a lazy future} 6 | \usage{ 7 | reset(x, ...) 8 | } 9 | \arguments{ 10 | \item{x}{A Future.} 11 | 12 | \item{\ldots}{Not used.} 13 | } 14 | \value{ 15 | \code{reset()} returns a lazy, vanilla \link{Future} that can be relaunched. 16 | Resetting a running future results in a \link{FutureError}. 17 | } 18 | \description{ 19 | A future that has successfully completed, \link[=cancel]{canceled}, interrupted, 20 | or has failed due to an error, can be relaunched after resetting it. 21 | } 22 | \details{ 23 | A lazy, vanilla \link{Future} can be reused in another R session. For 24 | instance, if we do: 25 | 26 | \if{html}{\out{
}}\preformatted{library(future) 27 | a <- 2 28 | f <- future(42 * a, lazy = TRUE) 29 | saveRDS(f, "myfuture.rds") 30 | }\if{html}{\out{
}} 31 | 32 | Then we can read and evaluate the future in another R session using: 33 | 34 | \if{html}{\out{
}}\preformatted{library(future) 35 | f <- readRDS("myfuture.rds") 36 | v <- value(f) 37 | print(v) 38 | #> [1] 84 39 | }\if{html}{\out{
}} 40 | } 41 | \examples{ 42 | ## Like mean(), but fails 90\% of the time 43 | shaky_mean <- function(x) { 44 | if (as.double(Sys.time()) \%\% 1 < 0.90) stop("boom") 45 | mean(x) 46 | } 47 | 48 | x <- rnorm(100) 49 | 50 | ## Calculate the mean of 'x' with a risk of failing randomly 51 | f <- future({ shaky_mean(x) }) 52 | 53 | ## Relaunch until success 54 | repeat({ 55 | v <- tryCatch(value(f), error = identity) 56 | if (!inherits(v, "error")) break 57 | message("Resetting failed future, and retry in 0.1 seconds") 58 | f <- reset(f) 59 | Sys.sleep(0.1) 60 | }) 61 | cat("mean:", v, "\n") 62 | } 63 | -------------------------------------------------------------------------------- /man/resetWorkers.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils_api-plan.R 3 | \name{resetWorkers} 4 | \alias{resetWorkers} 5 | \title{Free up active background workers} 6 | \usage{ 7 | resetWorkers(x, ...) 8 | } 9 | \arguments{ 10 | \item{x}{A FutureStrategy.} 11 | 12 | \item{\ldots}{Not used.} 13 | } 14 | \description{ 15 | Free up active background workers 16 | } 17 | \details{ 18 | This function will resolve any active futures that is currently 19 | being evaluated on background workers. 20 | } 21 | \examples{ 22 | resetWorkers(plan()) 23 | 24 | } 25 | \keyword{internal} 26 | -------------------------------------------------------------------------------- /man/resolved.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/core_api-resolved.R 3 | \name{resolved} 4 | \alias{resolved} 5 | \title{Check whether a future is resolved or not} 6 | \usage{ 7 | resolved(x, ...) 8 | } 9 | \arguments{ 10 | \item{x}{A \link{Future}, a list, or an environment (which also 11 | includes \link[listenv:listenv]{list environment}).} 12 | 13 | \item{\ldots}{Not used.} 14 | } 15 | \value{ 16 | A logical of the same length and dimensions as \code{x}. 17 | Each element is TRUE unless the corresponding element is a 18 | non-resolved future in case it is FALSE. 19 | } 20 | \description{ 21 | Check whether a future is resolved or not 22 | } 23 | \details{ 24 | This method needs to be implemented by the class that implement 25 | the Future API. The implementation should return either TRUE or FALSE 26 | and must never throw an error (except for \link{FutureError}:s which indicate 27 | significant, often unrecoverable infrastructure problems). 28 | It should also be possible to use the method for polling the 29 | future until it is resolved (without having to wait infinitely long), 30 | e.g. \code{while (!resolved(future)) Sys.sleep(5)}. 31 | } 32 | -------------------------------------------------------------------------------- /man/result.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/backend_api-Future-class.R 3 | \name{result.Future} 4 | \alias{result.Future} 5 | \alias{result} 6 | \title{Get the results of a resolved future} 7 | \usage{ 8 | \method{result}{Future}(future, ...) 9 | } 10 | \arguments{ 11 | \item{future}{A \link{Future}.} 12 | 13 | \item{\ldots}{Not used.} 14 | } 15 | \value{ 16 | The \link{FutureResult} object. 17 | } 18 | \description{ 19 | Get the results of a resolved future 20 | } 21 | \details{ 22 | This function is only part of the \emph{backend} Future API. 23 | This function is \emph{not} part of the frontend Future API. 24 | } 25 | \keyword{internal} 26 | -------------------------------------------------------------------------------- /man/run.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/backend_api-Future-class.R 3 | \name{run.Future} 4 | \alias{run.Future} 5 | \alias{run} 6 | \title{Run a future} 7 | \usage{ 8 | \method{run}{Future}(future, ...) 9 | } 10 | \arguments{ 11 | \item{future}{A \link{Future}.} 12 | 13 | \item{\ldots}{Not used.} 14 | } 15 | \value{ 16 | The \link{Future} object. 17 | } 18 | \description{ 19 | Run a future 20 | } 21 | \details{ 22 | This function can only be called once per future. 23 | Further calls will result in an informative error. 24 | If a future is not run when its value is queried, 25 | then it is run at that point. 26 | } 27 | \keyword{internal} 28 | -------------------------------------------------------------------------------- /man/save_rds.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-immediateCondition.R 3 | \name{save_rds} 4 | \alias{save_rds} 5 | \title{Robustly Saves an Object to RDS File Atomically} 6 | \usage{ 7 | save_rds(object, pathname, ...) 8 | } 9 | \arguments{ 10 | \item{object}{The \R object to be save.} 11 | 12 | \item{pathname}{RDS file to written.} 13 | 14 | \item{\ldots}{(optional) Additional arguments passed to \code{\link[base:readRDS]{base::saveRDS()}}.} 15 | } 16 | \value{ 17 | The pathname of the RDS written. 18 | } 19 | \description{ 20 | Robustly Saves an Object to RDS File Atomically 21 | } 22 | \details{ 23 | Uses \link[base:readRDS]{base::saveRDS} internally but writes the object atomically by first 24 | writing to a temporary file which is then renamed. 25 | } 26 | \keyword{internal} 27 | -------------------------------------------------------------------------------- /man/sequential.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/backend_api-11.SequentialFutureBackend-class.R 3 | \name{sequential} 4 | \alias{sequential} 5 | \alias{uniprocess} 6 | \title{Create a sequential future whose value will be in the current \R session} 7 | \usage{ 8 | sequential(..., gc = FALSE, earlySignal = FALSE, envir = parent.frame()) 9 | } 10 | \arguments{ 11 | \item{gc}{If TRUE, the garbage collector run (in the process that 12 | evaluated the future) only after the value of the future is collected. 13 | Exactly when the values are collected may depend on various factors such 14 | as number of free workers and whether \code{earlySignal} is TRUE (more 15 | frequently) or FALSE (less frequently). 16 | \emph{Some types of futures ignore this argument.}} 17 | 18 | \item{earlySignal}{Specified whether conditions should be signaled as soon 19 | as possible or not.} 20 | 21 | \item{envir}{The \link{environment} from where global objects should be 22 | identified.} 23 | 24 | \item{\ldots}{Additional named elements to \code{\link[=Future]{Future()}}.} 25 | } 26 | \value{ 27 | A \link{Future}. 28 | } 29 | \description{ 30 | \emph{WARNING: This function must never be called. 31 | It may only be used with \code{\link[=plan]{plan()}}} 32 | } 33 | \details{ 34 | A sequential future is a future that is evaluated sequentially in the 35 | current \R session similarly to how \R expressions are evaluated in \R. 36 | The only difference to \R itself is that globals are validated 37 | by default just as for all other types of futures in this package. 38 | 39 | This function is must \emph{not} be called directly. Instead, the 40 | typical usages are: 41 | 42 | \if{html}{\out{
}}\preformatted{# Evaluate futures sequentially in the current R process 43 | plan(sequential) 44 | }\if{html}{\out{
}} 45 | } 46 | \examples{ 47 | ## Use sequential futures 48 | plan(sequential) 49 | 50 | ## A global variable 51 | a <- 0 52 | 53 | ## Create a sequential future 54 | f <- future({ 55 | b <- 3 56 | c <- 2 57 | a * b * c 58 | }) 59 | 60 | ## Since 'a' is a global variable in future 'f' which 61 | ## is eagerly resolved (default), this global has already 62 | ## been resolved / incorporated, and any changes to 'a' 63 | ## at this point will _not_ affect the value of 'f'. 64 | a <- 7 65 | print(a) 66 | 67 | v <- value(f) 68 | print(v) 69 | stopifnot(v == 0) 70 | } 71 | -------------------------------------------------------------------------------- /man/sessionDetails.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils_api-sessionDetails.R 3 | \name{sessionDetails} 4 | \alias{sessionDetails} 5 | \title{Outputs details on the current \R session} 6 | \usage{ 7 | sessionDetails(env = FALSE) 8 | } 9 | \arguments{ 10 | \item{env}{If TRUE, \code{Sys.getenv()} information is returned.} 11 | } 12 | \value{ 13 | Invisibly a list of all details. 14 | } 15 | \description{ 16 | Outputs details on the current \R session 17 | } 18 | \keyword{internal} 19 | -------------------------------------------------------------------------------- /man/signalConditions.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/protected_api-signalConditions.R 3 | \name{signalConditions} 4 | \alias{signalConditions} 5 | \title{Signals Captured Conditions} 6 | \usage{ 7 | signalConditions( 8 | future, 9 | include = "condition", 10 | exclude = NULL, 11 | resignal = TRUE, 12 | ... 13 | ) 14 | } 15 | \arguments{ 16 | \item{future}{A resolved \link{Future}.} 17 | 18 | \item{include}{A character string of \link[base:conditions]{condition} 19 | classes to signal.} 20 | 21 | \item{exclude}{A character string of \link[base:conditions]{condition} 22 | classes \emph{not} to signal.} 23 | 24 | \item{resignal}{If TRUE, then already signaled conditions are signaled 25 | again, otherwise not.} 26 | 27 | \item{\ldots}{Not used.} 28 | } 29 | \value{ 30 | Returns the \link{Future} where conditioned that were signaled 31 | have been flagged to have been signaled. 32 | } 33 | \description{ 34 | Captured conditions that meet the \code{include} and \code{exclude} 35 | requirements are signaled \emph{in the order as they were captured}. 36 | } 37 | \seealso{ 38 | Conditions are signaled by 39 | \code{\link[base:conditions]{signalCondition}()}. 40 | } 41 | \keyword{internal} 42 | -------------------------------------------------------------------------------- /man/sticky_globals.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-sticky_globals.R 3 | \name{sticky_globals} 4 | \alias{sticky_globals} 5 | \title{Place a sticky-globals environment immediately after the global environment} 6 | \usage{ 7 | sticky_globals(erase = FALSE, name = "future:sticky_globals", pos = 2L) 8 | } 9 | \arguments{ 10 | \item{erase}{(logical) If TRUE, the environment is erased, otherwise not.} 11 | 12 | \item{name}{(character) The name of the environment on the \link[base:search]{base::search} 13 | path.} 14 | 15 | \item{pos}{(integer) The position on the search path where the 16 | environment should be positioned. If \code{pos == 0L}, then the environment 17 | is detached, if it exists.} 18 | } 19 | \value{ 20 | (invisible; environment) The environment. 21 | } 22 | \description{ 23 | Place a sticky-globals environment immediately after the global environment 24 | } 25 | \keyword{internal} 26 | -------------------------------------------------------------------------------- /man/usedCores.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/backend_api-11.MulticoreFutureBackend-class.R 3 | \name{usedCores} 4 | \alias{usedCores} 5 | \title{Get number of cores currently used} 6 | \usage{ 7 | usedCores() 8 | } 9 | \value{ 10 | A non-negative integer. 11 | } 12 | \description{ 13 | Get number of children (and don't count the current process) 14 | used by the current \R session. The number of children 15 | is the total number of subprocesses launched by this 16 | process that are still running and whose values have yet 17 | not been collected. 18 | } 19 | \keyword{internal} 20 | -------------------------------------------------------------------------------- /pkgdown/_pkgdown.yml.rsp: -------------------------------------------------------------------------------- 1 | <% 2 | pkgs_mapreduce <- c("future.apply", "doFuture", "furrr") 3 | pkgs_backend <- c("future.batchtools", "future.callr", "future.mirai") 4 | pkgs <- c("globals", "listenv", "parallelly", "future", "future.tests", "progressr", pkgs_mapreduce, pkgs_backend) 5 | pkgs_extra <- c("BiocParallel.FutureParam", "future.tools", "future.mapreduce", "marshal") 6 | pkgs <- c(sort(pkgs), pkgs_extra) 7 | urls <- sprintf("https://%s.futureverse.org", pkgs) 8 | names(urls) <- pkgs 9 | 10 | file <- file.path(c(".", ".."), "DESCRIPTION") 11 | file <- file[utils::file_test("-f", file)] 12 | pkg <- read.dcf(file)[,"Package"] 13 | 14 | #common_support <- c("future", "future.apply", "future.callr", "future.batchtools", "doFuture", "BiocParallel.FutureParam") 15 | %> 16 | url: https://<%= pkg %>.futureverse.org 17 | 18 | home: 19 | links: 20 | - text: Roadmap/Milestones 21 | href: https://github.com/<%= gsub("(^.*:|[.]git$)", "", subset(gert::git_remote_list(), name == "origin")$url) %>/milestones 22 | - text: The Futureverse Project 23 | href: https://www.futureverse.org/ 24 | - text: Futureverse User Forum 25 | href: https://github.com/futureverse/future/discussions 26 | 27 | navbar: 28 | structure: 29 | right: [search, futureverse, pkgs, cran, github, lightswitch] 30 | components: 31 | futureverse: 32 | icon: fas fa-home 33 | href: https://www.futureverse.org/ 34 | pkgs: 35 | text: Packages 36 | menu: 37 | <% for (name in names(urls)) { %> 38 | - text: <%= name %> <% if (name %in% pkgs_extra) { %>(experimental)<% } else if (name %in% pkgs_backend) { %>(backend)<% } else if (name %in% pkgs_mapreduce) { %>(map-reduce)<% } %> 39 | href: <%= urls[name] %> 40 | <% } %> 41 | cran: 42 | icon: fab fa-r-project 43 | href: https://cloud.r-project.org/package=<%= pkg %> 44 | 45 | search: 46 | exclude: ['README_ja.md'] 47 | 48 | template: 49 | params: 50 | docsearch: 51 | api_key: aa6e02fc501886fb0f7c91ac4e300456 52 | index_name: futureverse 53 | algoliaOptions: { 'facetFilters': ['project:<%= pkg %>'] } 54 | ganalytics: G-SB3EQSD9FR 55 | bootstrap: 5 56 | light-switch: true 57 | -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futureverse/future/83f2c3ecaf572daba957c07356d55e2cb2c955b6/pkgdown/favicon/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futureverse/future/83f2c3ecaf572daba957c07356d55e2cb2c955b6/pkgdown/favicon/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futureverse/future/83f2c3ecaf572daba957c07356d55e2cb2c955b6/pkgdown/favicon/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futureverse/future/83f2c3ecaf572daba957c07356d55e2cb2c955b6/pkgdown/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futureverse/future/83f2c3ecaf572daba957c07356d55e2cb2c955b6/pkgdown/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futureverse/future/83f2c3ecaf572daba957c07356d55e2cb2c955b6/pkgdown/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futureverse/future/83f2c3ecaf572daba957c07356d55e2cb2c955b6/pkgdown/favicon/favicon.ico -------------------------------------------------------------------------------- /revdep/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: dummy 2 | Version: 0.1 3 | Title: A Dummy Package 4 | Description: A package placeholder to trick 'usethis' to stop at the folder where this DESCRIPTION file lives rather than traversing higher up in the directory structure. This protects against bugs such as the one described in https://github.com/r-lib/lifecycle/issues/52. 5 | Authors@R: person("Dummy", "Dummyson", role="aut", email = "dummy@dummy.org") 6 | License: GPL (>= 3) 7 | Imports: 8 | lifecycle 9 | RdMacros: lifecycle 10 | -------------------------------------------------------------------------------- /revdep/R_FUTURE_CONNECTIONS_ONMISUSE=error/cran.md: -------------------------------------------------------------------------------- 1 | ## revdepcheck results 2 | 3 | We checked 426 reverse dependencies (404 from CRAN + 22 from Bioconductor), comparing R CMD check results across CRAN and dev versions of this package. 4 | 5 | * We saw 3 new problems 6 | * We failed to check 1 packages 7 | 8 | Issues with CRAN packages are summarised below. 9 | 10 | ### New problems 11 | (This reports the first line of each new failure) 12 | 13 | * doFuture 14 | checking tests ... 15 | 16 | * future.tests 17 | checking tests ... 18 | 19 | * sims 20 | checking tests ... 21 | 22 | ### Failed to check 23 | 24 | * TriDimRegression (NA) 25 | -------------------------------------------------------------------------------- /revdep/R_FUTURE_CONNECTIONS_ONMISUSE=error/failures.md: -------------------------------------------------------------------------------- 1 | # TriDimRegression 2 | 3 |
4 | 5 | * Version: 1.0.2 6 | * GitHub: https://github.com/alexander-pastukhov/tridim-regression 7 | * Source code: https://github.com/cran/TriDimRegression 8 | * Date/Publication: 2023-09-13 14:10:03 UTC 9 | * Number of recursive dependencies: 98 10 | 11 | Run `revdepcheck::revdep_details(, "TriDimRegression")` for more info 12 | 13 |
14 | 15 | ## In both 16 | 17 | * checking whether package ‘TriDimRegression’ can be installed ... ERROR 18 | ``` 19 | Installation failed. 20 | See ‘/c4/home/henrik/futureverse/future/revdep/checks/TriDimRegression/new/TriDimRegression.Rcheck/00install.out’ for details. 21 | ``` 22 | 23 | ## Installation 24 | 25 | ### Devel 26 | 27 | ``` 28 | * installing *source* package ‘TriDimRegression’ ... 29 | ** package ‘TriDimRegression’ successfully unpacked and MD5 sums checked 30 | ** using staged installation 31 | Error in loadNamespace(x) : there is no package called ‘rstantools’ 32 | Calls: loadNamespace -> withRestarts -> withOneRestart -> doWithOneRestart 33 | Execution halted 34 | ERROR: configuration failed for package ‘TriDimRegression’ 35 | * removing ‘/c4/home/henrik/futureverse/future/revdep/checks/TriDimRegression/new/TriDimRegression.Rcheck/TriDimRegression’ 36 | 37 | 38 | ``` 39 | ### CRAN 40 | 41 | ``` 42 | * installing *source* package ‘TriDimRegression’ ... 43 | ** package ‘TriDimRegression’ successfully unpacked and MD5 sums checked 44 | ** using staged installation 45 | Error in loadNamespace(x) : there is no package called ‘rstantools’ 46 | Calls: loadNamespace -> withRestarts -> withOneRestart -> doWithOneRestart 47 | Execution halted 48 | ERROR: configuration failed for package ‘TriDimRegression’ 49 | * removing ‘/c4/home/henrik/futureverse/future/revdep/checks/TriDimRegression/old/TriDimRegression.Rcheck/TriDimRegression’ 50 | 51 | 52 | ``` 53 | -------------------------------------------------------------------------------- /revdep/R_FUTURE_CONNECTIONS_ONMISUSE=error/notes.md: -------------------------------------------------------------------------------- 1 | # Notes 2 | 3 | ## Setup 4 | 5 | ```r 6 | options(Ncpus = 6L) 7 | install.packages("remotes") 8 | remotes::install_github("r-lib/revdepcheck") 9 | ``` 10 | 11 | ```sh 12 | ## Used by R itself 13 | $ revdep/run.R --preinstall RCurl XML 14 | ``` 15 | 16 | 17 | ## Pre-installation 18 | 19 | In order to run these checks successfully on a machine _without internet 20 | access_, make sure to first populate the 'crancache' cache by pre-installing 21 | all packages to be tested plus a few more. 22 | 23 | ```sh 24 | $ scl enable devtoolset-4 "revdep/run.R --preinstall blavaan" 25 | 26 | ## All packages to be tested 27 | $ revdep/run.R --preinstall-children 28 | ``` 29 | 30 | 31 | ## Testing 32 | 33 | ### Packages that require Internet 34 | 35 | The following packages will fail when tested in 'offline' mode because 36 | their examples or tests require a working internet connection: 37 | 38 | * BatchGetSymbols 39 | * datapackage.r 40 | * GetBCBData 41 | * GSODR 42 | * hackeRnews 43 | * iml 44 | * tableschema.r 45 | * tsfeatures 46 | 47 | 48 | ### Packages that fail if tested in parallel 49 | 50 | The following packages will fail when tested in parallel, because they 51 | compete with themselves for resources. For example, several Bioconductor 52 | package assumes their BiocFileCache folder is empty, or no other R 53 | processes are writing to it at the same time. 54 | 55 | * ... 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /revdep/R_FUTURE_GLOBALS_ONREFERENCE=error/cran.md: -------------------------------------------------------------------------------- 1 | ## revdepcheck results 2 | 3 | We checked 143 reverse dependencies (135 from CRAN + 8 from BioConductor), comparing R CMD check results across CRAN and dev versions of this package. 4 | 5 | * We saw 0 new problems 6 | * We failed to check 0 packages 7 | 8 | -------------------------------------------------------------------------------- /revdep/R_FUTURE_GLOBALS_ONREFERENCE=error/failures.md: -------------------------------------------------------------------------------- 1 | *Wow, no problems at all. :)* -------------------------------------------------------------------------------- /revdep/R_FUTURE_PLAN=multisession/cran.md: -------------------------------------------------------------------------------- 1 | ## revdepcheck results 2 | 3 | We checked 232 reverse dependencies (217 from CRAN + 15 from Bioconductor), comparing R CMD check results across CRAN and dev versions of this package. 4 | 5 | * We saw 0 new problems 6 | * We failed to check 1 packages 7 | 8 | Issues with CRAN packages are summarised below. 9 | 10 | ### Failed to check 11 | 12 | * foieGras (NA) 13 | -------------------------------------------------------------------------------- /revdep/R_FUTURE_RESOLVED_TIMEOUT=0/cran.md: -------------------------------------------------------------------------------- 1 | ## revdepcheck results 2 | 3 | We checked 168 reverse dependencies (159 from CRAN + 9 from Bioconductor), comparing R CMD check results across CRAN and dev versions of this package. 4 | 5 | * We saw 0 new problems 6 | * We failed to check 1 packages 7 | 8 | Issues with CRAN packages are summarised below. 9 | 10 | ### Failed to check 11 | 12 | * Signac (NA) 13 | -------------------------------------------------------------------------------- /revdep/R_FUTURE_RESOLVED_TIMEOUT=0/failures.md: -------------------------------------------------------------------------------- 1 | # Signac 2 | 3 |
4 | 5 | * Version: 1.1.1 6 | * GitHub: https://github.com/timoast/signac 7 | * Source code: https://github.com/cran/Signac 8 | * Date/Publication: 2021-02-03 23:50:09 UTC 9 | * Number of recursive dependencies: 241 10 | 11 | Run `revdep_details(, "Signac")` for more info 12 | 13 |
14 | 15 | ## In both 16 | 17 | * R CMD check timed out 18 | 19 | 20 | * checking dependencies in R code ... NOTE 21 | ``` 22 | Namespace in Imports field not imported from: 'SeuratObject' 23 | All declared Imports should be used. 24 | ``` 25 | 26 | -------------------------------------------------------------------------------- /revdep/R_FUTURE_RESOLVED_TIMEOUT=0/notes.md: -------------------------------------------------------------------------------- 1 | # Notes 2 | 3 | ## Setup 4 | 5 | ```r 6 | > options(Ncpus = 6L) 7 | > install.packages("remotes") 8 | > remotes::install_github("r-lib/revdepcheck") 9 | ``` 10 | 11 | ```sh 12 | ## Used by R itself 13 | $ revdep/run.R --preinstall RCurl XML 14 | ``` 15 | 16 | 17 | ## Pre-installation 18 | 19 | In order to run these checks successfully on a machine _without internet 20 | access_, make sure to first populate the 'crancache' cache by pre-installing 21 | all packages to be tested plus a few more. 22 | 23 | ```sh 24 | $ scl enable devtoolset-4 "revdep/run.R --preinstall blavaan" 25 | 26 | ## All packages to be tested 27 | $ revdep/run.R --preinstall-children 28 | ``` 29 | 30 | 31 | ## Testing 32 | 33 | ### Package that requires Internet 34 | 35 | The following packages will fail when tested in 'offline' mode because 36 | their examples or tests require a working internet connection: 37 | 38 | * BatchGetSymbols 39 | * datapackage.r 40 | * GetBCBData 41 | * GSODR 42 | * hackeRnews 43 | * iml 44 | * tableschema.r 45 | * tsfeatures 46 | -------------------------------------------------------------------------------- /revdep/cran.md: -------------------------------------------------------------------------------- 1 | ## revdepcheck results 2 | 3 | We checked 434 reverse dependencies (366 from CRAN + 68 from Bioconductor), comparing R CMD check results across CRAN and dev versions of this package. 4 | 5 | * We saw 0 new problems 6 | * We failed to check 0 packages 7 | 8 | -------------------------------------------------------------------------------- /revdep/notes.md: -------------------------------------------------------------------------------- 1 | # Notes 2 | 3 | ## Setup 4 | 5 | ```r 6 | options(Ncpus = 6L) 7 | install.packages("remotes") 8 | remotes::install_github("r-lib/revdepcheck") 9 | ``` 10 | 11 | ```sh 12 | ## Used by R itself 13 | $ revdep/run.R --preinstall RCurl XML 14 | ``` 15 | 16 | 17 | ## Pre-installation 18 | 19 | In order to run these checks successfully on a machine _without internet 20 | access_, make sure to first populate the 'crancache' cache by pre-installing 21 | all packages to be tested plus a few more. 22 | 23 | ```sh 24 | $ scl enable devtoolset-4 "revdep/run.R --preinstall blavaan" 25 | 26 | ## All packages to be tested 27 | $ revdep/run.R --preinstall-children 28 | ``` 29 | 30 | 31 | ## Testing 32 | 33 | ### Packages that require Internet 34 | 35 | The following packages will fail when tested in 'offline' mode because 36 | their examples or tests require a working internet connection: 37 | 38 | * BatchGetSymbols 39 | * datapackage.r 40 | * GetBCBData 41 | * GSODR 42 | * hackeRnews 43 | * iml 44 | * tableschema.r 45 | * tsfeatures 46 | 47 | 48 | ### Packages that fail if tested in parallel 49 | 50 | The following packages will fail when tested in parallel, because they 51 | compete with themselves for resources. For example, several Bioconductor 52 | package assumes their BiocFileCache folder is empty, or no other R 53 | processes are writing to it at the same time. 54 | 55 | * ... 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /revdep/revdepcheck.Renviron: -------------------------------------------------------------------------------- 1 | ## Environment variables set by revdepcheck.extras::run() 2 | R_REVDEPCHECK_TIMEOUT=${R_REVDEPCHECK_TIMEOUT:-180} 3 | TAR_SKIP_CLUSTERMQ=${TAR_SKIP_CLUSTERMQ-true} 4 | 5 | ## Turn on more checks 6 | # NOT_CRAN=true 7 | 8 | ## Allow for at least two workers 9 | R_PARALLELLY_AVAILABLECORES_FALLBACK=2 10 | -------------------------------------------------------------------------------- /revdep/run.R: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env Rscript 2 | 3 | precheck <- function() { 4 | ## WORKAROUND: Remove checked pkgs that use file links, which otherwise 5 | ## produce warnings which are promoted to errors by revdepcheck. 6 | unlink("revdep/checks/aroma.affymetrix", recursive = TRUE) 7 | } 8 | 9 | revdepcheck.extras::run() 10 | -------------------------------------------------------------------------------- /revdep/run.pbs: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## Example: qsub -l nodes=1:ppn=24 -l vmem=30gb revdep/run.pbs 3 | #PBS -j oe # Join STDERR and STDOUT 4 | cd "$PBS_O_WORKDIR" 5 | 6 | module load r 7 | Rscript revdep/run.R 8 | -------------------------------------------------------------------------------- /revdep/run.sge: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## Example: qsub -pe smp 24 -l h_rt=08:00:00 revdep/run.sge 3 | #$ -S /bin/bash 4 | #$ -R yes # SGE host reservation, highly recommended 5 | #$ -cwd # Current working directory 6 | #$ -j y # Join STDERR and STDOUT 7 | #$ -l mem_free=3G # On average 4 GiB of RAM per core (=a package check) 8 | #$ -m bea # email when job (b)egins, (e)nds, or (a)borts 9 | # 10 | # Pass on R-specific environment variables, iff set: 11 | ##$ -v _R_CHECK_LENGTH_1_CONDITION_ 12 | ##$ -v _R_CHECK_LENGTH_1_LOGIC2_ 13 | ##$ -v R_STARTUP_DEBUG 14 | 15 | ## SPECIAL: On Wynton HPC 16 | if [[ $SGE_CLUSTER_NAME == *wynton* ]]; then 17 | module load CBI 18 | module load r 19 | # module load r/4.0.0-alpha 20 | 21 | ## Some packages need a more modern version of gcc, e.g. 'balvaan' 22 | module load CBI-testing 23 | module load scl-devtoolset/4 24 | 25 | ## Some packages require non-default system libraries 26 | module load gdal geos gsl hdf5 jags 27 | 28 | ## Report on what modules are in use 29 | module list 30 | 31 | ## Install all packages to toward $TMPDIR, if revdep/library doesn't already exist. 32 | ## This will avoid some of the slowness on the global file system 33 | #if [[ ! -d revdep/library ]]; then 34 | # tmpdir=$(mktemp -d) 35 | # ln -fs "$tmpdir" revdep/library 36 | # [[ -d revdep/library ]] || { >&2 echo "ERROR: Failed to link revdep/library/ to $tmpdir"; exit 1; } 37 | #fi 38 | 39 | ## To check in on revdep/library/ on the running host (see below), submit a job like: 40 | ## echo "ls -lR revdep/library/" | qsub -cwd -j yes -l hostname= 41 | 42 | ## Assert that revdep/library is on $TMPDIR 43 | #if [[ ! "$(readlink revdep/library)" = $TMPDIR* ]]; then 44 | # >&2 echo "ERROR: revdep/library/ already exists but is not on $TMPDIR" 45 | # exit 1 46 | #fi 47 | fi 48 | 49 | echo "HOSTNAME: $HOSTNAME" 50 | ls -l revdep/ 51 | 52 | Rscript --version 53 | Rscript -e ".libPaths()" 54 | Rscript revdep/run.R 55 | -------------------------------------------------------------------------------- /tests/test-000.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-000.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("000") 4 | -------------------------------------------------------------------------------- /tests/test-FutureError.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-FutureError.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("FutureError") 4 | -------------------------------------------------------------------------------- /tests/test-FutureGlobals.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-FutureGlobals.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("FutureGlobals") 4 | -------------------------------------------------------------------------------- /tests/test-FutureRegistry.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-FutureRegistry.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("FutureRegistry") 4 | -------------------------------------------------------------------------------- /tests/test-adhoc_native_to_utf8.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-adhoc_native_to_utf8.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("adhoc_native_to_utf8") 4 | -------------------------------------------------------------------------------- /tests/test-backtrace.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-backtrace.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("backtrace") 4 | -------------------------------------------------------------------------------- /tests/test-bquote.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-bquote.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("bquote") 4 | -------------------------------------------------------------------------------- /tests/test-cancel.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-cancel.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("cancel") 4 | -------------------------------------------------------------------------------- /tests/test-capture_journals.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-capture_journals.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("capture_journals") 4 | -------------------------------------------------------------------------------- /tests/test-cluster,worker-termination.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-cluster,worker-termination.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("cluster,worker-termination") 4 | -------------------------------------------------------------------------------- /tests/test-cluster-connection-clashes.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-cluster-connection-clashes.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("cluster-connection-clashes") 4 | -------------------------------------------------------------------------------- /tests/test-cluster-missing-future-pkg.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-cluster-missing-future-pkg.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("cluster-missing-future-pkg") 4 | -------------------------------------------------------------------------------- /tests/test-demo-fibonacci.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-demo-fibonacci.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("demo-fibonacci") 4 | -------------------------------------------------------------------------------- /tests/test-demo-mandelbrot.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-demo-mandelbrot.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("demo-mandelbrot") 4 | -------------------------------------------------------------------------------- /tests/test-dotdotdot.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-dotdotdot.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("dotdotdot") 4 | -------------------------------------------------------------------------------- /tests/test-early-signaling.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-early-signaling.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("early-signaling") 4 | -------------------------------------------------------------------------------- /tests/test-error_on_warn_2.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-error_on_warn_2.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("error_on_warn_2") 4 | -------------------------------------------------------------------------------- /tests/test-future,labels.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-future,labels.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("future,labels") 4 | -------------------------------------------------------------------------------- /tests/test-future,optsenvvars.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-future,optsenvvars.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("future,optsenvvars") 4 | -------------------------------------------------------------------------------- /tests/test-future.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-future.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("future") 4 | -------------------------------------------------------------------------------- /tests/test-futureAssign.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-futureAssign.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("futureAssign") 4 | -------------------------------------------------------------------------------- /tests/test-futureAssign_OP.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-futureAssign_OP.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("futureAssign_OP") 4 | -------------------------------------------------------------------------------- /tests/test-futureAssign_OP_with_environment.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-futureAssign_OP_with_environment.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("futureAssign_OP_with_environment") 4 | -------------------------------------------------------------------------------- /tests/test-futureAssign_OP_with_listenv.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-futureAssign_OP_with_listenv.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("futureAssign_OP_with_listenv") 4 | -------------------------------------------------------------------------------- /tests/test-futureCall.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-futureCall.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("futureCall") 4 | -------------------------------------------------------------------------------- /tests/test-futureOf.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-futureOf.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("futureOf") 4 | -------------------------------------------------------------------------------- /tests/test-futureOf_with_environment.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-futureOf_with_environment.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("futureOf_with_environment") 4 | -------------------------------------------------------------------------------- /tests/test-futureOf_with_listenv.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-futureOf_with_listenv.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("futureOf_with_listenv") 4 | -------------------------------------------------------------------------------- /tests/test-futureSessionInfo.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-futureSessionInfo.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("futureSessionInfo") 4 | -------------------------------------------------------------------------------- /tests/test-futures.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-futures.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("futures") 4 | -------------------------------------------------------------------------------- /tests/test-globals,NSE.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-globals,NSE.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("globals,NSE") 4 | -------------------------------------------------------------------------------- /tests/test-globals,S4methods.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-globals,S4methods.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("globals,S4methods") 4 | -------------------------------------------------------------------------------- /tests/test-globals,formulas.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-globals,formulas.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("globals,formulas") 4 | -------------------------------------------------------------------------------- /tests/test-globals,locals.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-globals,locals.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("globals,locals") 4 | -------------------------------------------------------------------------------- /tests/test-globals,manual.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-globals,manual.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("globals,manual") 4 | -------------------------------------------------------------------------------- /tests/test-globals,packages.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-globals,packages.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("globals,packages") 4 | -------------------------------------------------------------------------------- /tests/test-globals,resolve.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-globals,resolve.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("globals,resolve") 4 | -------------------------------------------------------------------------------- /tests/test-globals,subassignment.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-globals,subassignment.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("globals,subassignment") 4 | -------------------------------------------------------------------------------- /tests/test-globals,toolarge.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-globals,toolarge.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("globals,toolarge") 4 | -------------------------------------------------------------------------------- /tests/test-globals,tricky.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-globals,tricky.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("globals,tricky") 4 | -------------------------------------------------------------------------------- /tests/test-globals,tricky2.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-globals,tricky2.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("globals,tricky2") 4 | -------------------------------------------------------------------------------- /tests/test-globals,tricky_recursive.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-globals,tricky_recursive.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("globals,tricky_recursive") 4 | -------------------------------------------------------------------------------- /tests/test-globalsOf,tweaks.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-globalsOf,tweaks.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("globalsOf,tweaks") 4 | -------------------------------------------------------------------------------- /tests/test-immediateCondition.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-immediateCondition.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("immediateCondition") 4 | -------------------------------------------------------------------------------- /tests/test-interrupts-from-worker-itself.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-interrupts-from-worker-itself.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("interrupts-from-worker-itself") 4 | -------------------------------------------------------------------------------- /tests/test-invalid-owner.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-invalid-owner.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("invalid-owner") 4 | -------------------------------------------------------------------------------- /tests/test-makeClusterFuture.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-makeClusterFuture.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("makeClusterFuture") 4 | -------------------------------------------------------------------------------- /tests/test-mandelbrot.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-mandelbrot.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("mandelbrot") 4 | -------------------------------------------------------------------------------- /tests/test-misuse-connections.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-misuse-connections.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("misuse-connections") 4 | -------------------------------------------------------------------------------- /tests/test-mpi.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-mpi.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("mpi") 4 | -------------------------------------------------------------------------------- /tests/test-multicore,multithreading.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-multicore,multithreading.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("multicore,multithreading") 4 | -------------------------------------------------------------------------------- /tests/test-multicore,worker-termination.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-multicore,worker-termination.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("multicore,worker-termination") 4 | -------------------------------------------------------------------------------- /tests/test-multisession-libpaths.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-multisession-libpaths.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("multisession-libpaths") 4 | -------------------------------------------------------------------------------- /tests/test-nbrOfWorkers.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-nbrOfWorkers.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("nbrOfWorkers") 4 | -------------------------------------------------------------------------------- /tests/test-nested_futures,mc.cores.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-nested_futures,mc.cores.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("nested_futures,mc.cores") 4 | -------------------------------------------------------------------------------- /tests/test-nested_futures.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-nested_futures.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("nested_futures") 4 | -------------------------------------------------------------------------------- /tests/test-non-exportable,connections.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-non-exportable,connections.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("non-exportable,connections") 4 | -------------------------------------------------------------------------------- /tests/test-objectSize.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-objectSize.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("objectSize") 4 | -------------------------------------------------------------------------------- /tests/test-plan.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-plan.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("plan") 4 | -------------------------------------------------------------------------------- /tests/test-relaying,muffle.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-relaying,muffle.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("relaying,muffle") 4 | -------------------------------------------------------------------------------- /tests/test-relaying,split.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-relaying,split.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("relaying,split") 4 | -------------------------------------------------------------------------------- /tests/test-relaying.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-relaying.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("relaying") 4 | -------------------------------------------------------------------------------- /tests/test-requestCore.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-requestCore.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("requestCore") 4 | -------------------------------------------------------------------------------- /tests/test-requestNode.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-requestNode.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("requestNode") 4 | -------------------------------------------------------------------------------- /tests/test-reserved-keyword-functions.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-reserved-keyword-functions.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("reserved-keyword-functions") 4 | -------------------------------------------------------------------------------- /tests/test-reset.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-reset.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("reset") 4 | -------------------------------------------------------------------------------- /tests/test-resolve.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-resolve.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("resolve") 4 | -------------------------------------------------------------------------------- /tests/test-resolved-non-blocking-test.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-resolved-non-blocking-test.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("resolved-non-blocking-test") 4 | -------------------------------------------------------------------------------- /tests/test-rng.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-rng.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("rng") 4 | -------------------------------------------------------------------------------- /tests/test-rng_utils.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-rng_utils.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("rng_utils") 4 | -------------------------------------------------------------------------------- /tests/test-sequential.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-sequential.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("sequential") 4 | -------------------------------------------------------------------------------- /tests/test-sessionDetails.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-sessionDetails.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("sessionDetails") 4 | -------------------------------------------------------------------------------- /tests/test-startup-onAttach.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-startup-onAttach.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("startup-onAttach") 4 | -------------------------------------------------------------------------------- /tests/test-startup-onLoad.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-startup-onLoad.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("startup-onLoad") 4 | -------------------------------------------------------------------------------- /tests/test-startup-parseCmdArgs.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-startup-parseCmdArgs.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("startup-parseCmdArgs") 4 | -------------------------------------------------------------------------------- /tests/test-stdout.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-stdout.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("stdout") 4 | -------------------------------------------------------------------------------- /tests/test-timeouts.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-timeouts.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("timeouts") 4 | -------------------------------------------------------------------------------- /tests/test-tweak.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-tweak.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("tweak") 4 | -------------------------------------------------------------------------------- /tests/test-utils.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-utils.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("utils") 4 | -------------------------------------------------------------------------------- /tests/test-uuid.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-uuid.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("uuid") 4 | -------------------------------------------------------------------------------- /tests/test-value-error-cancels-set.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-value-error-cancels-set.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("value-error-cancels-set") 4 | -------------------------------------------------------------------------------- /tests/test-value.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-value.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("value") 4 | -------------------------------------------------------------------------------- /tests/test-whichIndex.R: -------------------------------------------------------------------------------- 1 | ## This runs testme test script inst/testme/test-whichIndex.R 2 | ## Don't edit - it was autogenerated by inst/testme/deploy.R 3 | future:::testme("whichIndex") 4 | --------------------------------------------------------------------------------