package par_incr
Install
dune-project
Dependency
Authors
Maintainers
Sources
md5=5cce5d774cc1b1f941e7a30bcce86a8e
sha512=7bdf75135eedef8ab41dc5cdf8f09acde6614b4a2f9ee2aec6c05d450cb5c4c82121fe89b5b8db8441ab63dcf8e59a46e6829ca854bfb564ddf94950e85ba668
doc/par_incr/Par_incr/index.html
Module Par_incrSource
A simple library for parallel incremental computations. Based on "Efficient Parallel Self-Adjusting Computation".
How it works
- Define
Var.twith certain values. - Perform
Var.watchoperation onVar.tand change it toincremental. - Every
incrementalsignifies a computation in itself. - Use different combinators provided by the library on the
incrementals and make even biggerincrementals. - Obtain value of a certain
incrementalby running it (arunoperation is provided by the library). - Running an
'a incrementalreturns a'a computation. - When we change some
Var.t(done withVar.setoperation), it marks all dependent computations dirty. - Running
propagateoperation on a dirtycomputationupdates its value efficiently. - Destroy (with
destroy_compoperation)computationwhen its no more required.
Par_incr Module Documentation
A 'a t holds a value of type 'a. This type is opaque and we don't expose any mechanism to change this or modify it. Computations happens by chaining together various combinators provided by the library, all of which operate on 'a t.
A 'a computation holds everything necessary to store a computation.
An executor is something that has to be passed while initially running the computation. The reason behind this is, we want to support multiple ways to run computations in parallel and library users can use the one that is best for them.
Suppose you have your own scheduler built on top of Domains and you don't want to use Domainslib for running tasks. You can very well use it as long as you provide these two run and par_do functions.
If however you want to use Domainslib, you would have an executor which would look roughly like this:
module T = Domainslib.Task
let pool = T.setup_pool ~num_domains:(Domain.recommended_domain_count () / 2) ()
let par_runner f = T.run pool f
let par_do l r =
let lres = T.async pool l in
let rres = r () in
(T.await pool lres, rres)
let executor = {run = par_runner; par_do}map ~fn a maps the internal value of a to fn. Default cutoff is Phys_equal.
combine a b is useful function to combine two incremental's into one.
bind ~fn a calls fn with the value of a and returns that. This lets us build computations that are more dynamic in nature. This is the monadic bind operation for incrementals.
delay f lets us have incrementals that are lazily evaluated.
value c returns the value/result associated with the computation c.
run ~executor t evaluates t with the provided executor. This stores the result of the computation as well as all the data structures associated with it.
propagate c will propagate the changes to all the Var.t that the computation c depended on. If there are no changes, it will not do any extra work and returns back right away.
dump_tree file c will dump the computation tree associated with c into file. It dumps the tree in D2 format. See the instructions for viewing the files.
destroy_comp c will destroy the computation associated with c. After destroying, calling propagate on c will result in an exception. It's necessary to destroy computations that are no longer needed. A computation will be taking up memory and doing unnecessary work if not destroyed.