Code Structure
When reviewing client Lisp code, we
encountered and collected a number of code patterns, which are not
only ineffective - but even rather bad in the context of
performance and memory usage.
Such cases are collected here for analysis and
documentation - and how to avoid bottlenecks.
1. local DEFUN blocks :
(defun mainFunc ( /
localFunc )
;; some code
(defun localFunc ()
;; some local
code
)
;; some code
)
If the "mainFunc" function is often called,
the local definition of "localFunc" becomes a performance
bottleneck.
Other than with compiled languages, the Lisp
interpreter always re-evaluates the local defun block, and
re-creates that local function, while the local function does not
change at runtime, of course.
It also does not make a difference whether
"localFunc" is declared as a local symbol (in "mainFunc") or not -
the only difference for a locally declared function is, that the
function body is automatically set as NIL when the code flow leaves
"mainFunc";
otherwise, when not declared locally, the
"localFunc" function becomes a global one (at global scope) and is
redefined as global function when "mainFunc" is re-entered
again.
So in any case, the repeated evaluation of
(defun localFunc ...) code block creates unnecessary performance
overhead, and additionally fills the Lisp memory, triggering more
GarbageCollections.
Suggestion :
even as possible from technical point, it does
not make real sense - except, when several main functions all
declare + use a same-named local function. Therefore, it is best to
avoid such code designs for better performance and less memory
load.
2. (while) loop iterating over a list :
(while (setq item (car
lst))
(setq lst (cdr lst))
;; some code
)
better approach :
(foreach item lst
;; some code
)
The (foreach) loop saves 4 operations
:
(setq item (car lst)) - 2 operations : (car) and
(setq)
(setq lst (cdr lst)) - 2 operations : (cdr)
and (setq)
so it reduces execution time by 4 operations
for each loop cycle, and many temporary Lisp objects, as "item" and
"lst" variables are reassigned new values with each
cycle;
such temporary objects fill the Lisp memory
and trigger earlier GarbageCollections, which in turn also reduce
the overall performance.
© Menhirs NV. All rights reserved. |