For the scheduled goals, ECLiPSe uses an execution model which is based on goal priorities and which guarantees that a scheduled goal with a higher priority will be always executed before any goal with lower priority. Priority is a small integer number ranging from 1 to 12, 1 being the highest priority and 12 the lowest (cf. figure 18.1). Each goal which is being executed is executed under a current priority. The priority of the currently executing goal can be determined with get_priority/1. This priority is
All goals started from the ECLiPSe top-level loop or from the command line with the -e option have priority 12.
Priority-based execution is driven by a scheduler: it picks up the scheduled suspension with the highest scheduling priority. If its scheduling priority is higher than the priority of the currently executing goal, then the execution of the current goal is interrupted and the new suspension is executed under its run_priority (which may be higher than the scheduling priority). This is repeated until there are no suspensions with priority higher than that of the current goal.
Note that suspensions have two distinct priorities attached: the scheduling priority determining the order of execution, and the run_priority determining the atomicity of execution.
It is also possible to execute a goal with a given priority by means of call_priority(Goal, Prio) which calls Goal with the priority Prio. When a goal is called this way with high priority, it is effectively made atomic, i.e., it will not be interrupted by goals with lower priority that wake up while it executes. Those goals will all be deferred until exit from call_priority/2. This technique can sometimes improve efficiency. Consider for example the following program:
p(1). report(Term) :- writeln(term=Term), suspend(report(Term),3,Term->inst).
and the execution
[eclipse 2]: report(f(X,Y,Z)), p(X),p(Y),p(Z). term = f(X, Y, Z) term = f(1, Y, Z) term = f(1, 1, Z) term = f(1, 1, 1)
report/1 is woken and executed three times, once for each variable binding. If instead we do the three bindings under high priority, it will only execute once after all bindings have already been done:
[eclipse 3]: report(f(X,Y,Z)), call_priority((p(X),p(Y),p(Z)), 2). term = f(X, Y, Z) term = f(1, 1, 1)
Note that woken goals are automatically executed under their run_priority (default 2), which usually make the use of call_priority(Goal, Prio) unnecessary.
Although the programmer is more or less free to specify which priorities to use, we strongly recommend to stick to the following scheme (from urgent to less urgent):
- debugging (1)
- goals which don’t contribute to the semantics of the program and always succeed, e.g., display routines, consistency checks or data breakpoints.
- immediate
- goals which should be woken immediately and which do not do any bindings or other updates. Examples are quick tests which can immediately fail and thus avoid redundant execution.
- quick
- fast deterministic goals which may propagate changes to other variables.
- normal
- deterministic goals which should be woken after the quick class.
- slow
- deterministic goals which require a lot of processing, e.g., complicated disjunctive constraints.
- delayed
- nondeterministic goals or goals which are extremely slow.
- toplevel goal (12)
- the default priority of the user program.