Skip to content

Instantly share code, notes, and snippets.

@mndrix
Last active December 20, 2015 04:29
Show Gist options
  • Save mndrix/6071506 to your computer and use it in GitHub Desktop.
Save mndrix/6071506 to your computer and use it in GitHub Desktop.
Toying with Amalog concurrency
// ack +Dir +Language +Pattern -File -Line
//
// True if File is beneath the directory Dir, written in Language and contains
// a Line that matches Pattern. Similar to the command line tool ack.
ack Dir Language Pattern File Line
dir_entry Dir Entry
type Entry file
fan_out 1 // optional optimization. See Note_fan_out
language Entry Language
line Entry Line
Line ~~ Pattern
// The concurrent_generator declaration says "generate choicepoints from dir_entry/2
// independently, buffering up to 4 results at a time, allowing the calling code to
// investigate choice points concurrently as they're created"
//
// Internally, this is sort of like creating a goroutine for dir_entry/2 and having
// it send solutions down a channel to the main thread of execution. This is done
// with a directive because the predicate is most likely to know how slowly it will
// generate choicepoints. A predicate like between/3 wouldn't use concurrent_generator.
//
// The idea is that one can write a predicate just as one normally would. When he
// learns that it can benefit from concurrency, he adds this single directive and realizes
// performance improvements.
:- concurrent_generator 4 dir_entry/2
...
// Note_fan_out:
// The goal fan_out/1 tells the runtime that outstanding choicepoints should be
// investigated concurrently with up to N threads per core. It's a way of
// saying, "We've created choicepoints for every possible solution, searching
// each choicepoint is going to be slow, so use multiple cores to make it faster"
//
// It doesn't matter how the choicepoints were created. If a cut discards some
// choicepoints that are being investigated in a separate thread, those threads
// stop and their work is discarded. In that scenario, it allows speculative
// execution.
main
maplist
spawn factor // spawn is an optional optimization
[huge,numbers,go,here]
ManyFactors
do_something_with_factors ManyFactors
// factor +N -Factors
//
// True if N is composed of a list of prime Factors.
// This predicate is expensive for large N.
// spawn/N is like call/N except it creates a communicating sequential process
// to seek the goal. spawn returns immediately. Each solution the process
// finds is communicated by binding variables in the spawning process. If
// the spawning process tries to unify with a variable whose value comes from
// a spawned process, it blocks until the value is available. If no solutions
// are found, unification fails.
//
// This technique is conceptually similar to Go's goroutines and channels except
// the details are all implicit. One achieves concurrency by simply wrapping an
// existing goal in spawn/N. Details like channels, receiving values, unpacking
// values, closing channels, are all done automatically by the runtime.
//
// One weakness of this model is that communication is only from child to parent.
// There's no mechanism for the spawning process to communicate additional
// information to the spawned process.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment