Content-Type: multipart/related; boundary="------------000405000507010404030802" --------------000405000507010404030802 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit According to the Hyperspec:
"let and let* create new variable bindings and execute a series of forms that use these bindings. let performs the bindings in parallel and let* does them sequentially. "
I thought I knew what that meant until I tried to demonstrate it to myself. I wrote a simple function that eats cpu cycles for a visible period of time. Then I set up a let expression which I thought would evaluate these forms in parallel:

(defun waste-time (n)
  (let ((a 0))
    (dotimes (i n a)
      (incf a (- (random 1.0) 0.5)))))

(let ((n 100000000))
  (let ((n1 (waste-time n))
        (n2 (waste-time n)))
    (print n1)
    (print n2)))

I have a quad-core i7 running Linux  3.2.0-33-generic #52-Ubuntu SMP Thu Oct 18 16:29:15 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux.

I built a fresh copy of SBCL with --fancy (which includes threading I believe) which I cloned via git this morning.

What I expected to see was two cpu cores busy for a few seconds when I run this. But what I in fact see is a single thread running. This indicates it is evaluating the let bindings serially, not in parallel.

If I wrap the code with (time ) I get this for the parallel let:

362.691
1979.4808
Evaluation took:
  3.815 seconds of real time
  3.816238 seconds of total run time (3.816238 user, 0.000000 system)
  100.03% CPU
  8,753,527,227 processor cycles
  30,000 bytes consed
 
And I get this for the serial let*:

-2341.4565
436.2103
Evaluation took:
  3.783 seconds of real time
  3.780236 seconds of total run time (3.780236 user, 0.000000 system)
  99.92% CPU
  8,680,021,725 processor cycles
  33,168 bytes consed



So I don't understand what the difference is, other than the compiler not being willing to recognize sequential bindings in the case of let vs let*.

Regards,
Jeff
--------------000405000507010404030802 Content-Type: text/html; charset=ISO-8859-1; name="s_let_l.htm" Content-Transfer-Encoding: 7bit Content-ID: Content-Disposition: inline; filename="s_let_l.htm" CLHS: Special Operator LET, LET*

[LISPWORKS][Common Lisp HyperSpec (TM)] [Previous][Up][Next]


Special Operator LET, LET*

Syntax:

let ({var | (var [init-form])}*) declaration* form* => result*

let* ({var | (var [init-form])}*) declaration* form* => result*

Arguments and Values:

var---a symbol.

init-form---a form.

declaration---a declare expression; not evaluated.

form---a form.

results---the values returned by the forms.

Description:

let and let* create new variable bindings and execute a series of forms that use these bindings. let performs the bindings in parallel and let* does them sequentially.

The form

 (let ((var1 init-form-1)
       (var2 init-form-2)
       ...
       (varm init-form-m))
   declaration1
   declaration2
   ...
   declarationp
   form1
   form2
   ...
   formn)
first evaluates the expressions init-form-1, init-form-2, and so on, in that order, saving the resulting values. Then all of the variables varj are bound to the corresponding values; each binding is lexical unless there is a special declaration to the contrary. The expressions formk are then evaluated in order; the values of all but the last are discarded (that is, the body of a let is an implicit progn).

let* is similar to let, but the bindings of variables are performed sequentially rather than in parallel. The expression for the init-form of a var can refer to vars previously bound in the let*.

The form

 (let* ((var1 init-form-1)
        (var2 init-form-2)
        ...
        (varm init-form-m))
   declaration1
   declaration2
   ...
   declarationp
   form1
   form2
   ...
   formn)
first evaluates the expression init-form-1, then binds the variable var1 to that value; then it evaluates init-form-2 and binds var2, and so on. The expressions formj are then evaluated in order; the values of all but the last are discarded (that is, the body of let* is an implicit progn).

For both let and let*, if there is not an init-form associated with a var, var is initialized to nil.

The special form let has the property that the scope of the name binding does not include any initial value form. For let*, a variable's scope also includes the remaining initial value forms for subsequent variable bindings.

Examples:

 (setq a 'top) =>  TOP
 (defun dummy-function () a) =>  DUMMY-FUNCTION
 (let ((a 'inside) (b a))
    (format nil "~S ~S ~S" a b (dummy-function))) =>  "INSIDE TOP TOP" 
 (let* ((a 'inside) (b a))
    (format nil "~S ~S ~S" a b (dummy-function))) =>  "INSIDE INSIDE TOP" 
 (let ((a 'inside) (b a))
    (declare (special a))
    (format nil "~S ~S ~S" a b (dummy-function))) =>  "INSIDE TOP INSIDE"

The code

 (let (x)
   (declare (integer x))
   (setq x (gcd y z))
   ...)
is incorrect; although x is indeed set before it is used, and is set to a value of the declared type integer, nevertheless x initially takes on the value nil in violation of the type declaration.

Affected By: None.

Exceptional Situations: None.

See Also:

progv

Notes: None.


The following X3J13 cleanup issues, not part of the specification, apply to this section:


[Starting Points][Contents][Index][Symbols][Glossary][Issues]
Copyright 1996-2005, LispWorks Ltd. All rights reserved.

--------------000405000507010404030802 Content-Type: text/html; charset=ISO-8859-1; name="s_let_l.htm" Content-Transfer-Encoding: 7bit Content-ID: Content-Disposition: inline; filename="s_let_l.htm" CLHS: Special Operator LET, LET*

[LISPWORKS][Common Lisp HyperSpec (TM)] [Previous][Up][Next]


Special Operator LET, LET*

Syntax:

let ({var | (var [init-form])}*) declaration* form* => result*

let* ({var | (var [init-form])}*) declaration* form* => result*

Arguments and Values:

var---a symbol.

init-form---a form.

declaration---a declare expression; not evaluated.

form---a form.

results---the values returned by the forms.

Description:

let and let* create new variable bindings and execute a series of forms that use these bindings. let performs the bindings in parallel and let* does them sequentially.

The form

 (let ((var1 init-form-1)
       (var2 init-form-2)
       ...
       (varm init-form-m))
   declaration1
   declaration2
   ...
   declarationp
   form1
   form2
   ...
   formn)
first evaluates the expressions init-form-1, init-form-2, and so on, in that order, saving the resulting values. Then all of the variables varj are bound to the corresponding values; each binding is lexical unless there is a special declaration to the contrary. The expressions formk are then evaluated in order; the values of all but the last are discarded (that is, the body of a let is an implicit progn).

let* is similar to let, but the bindings of variables are performed sequentially rather than in parallel. The expression for the init-form of a var can refer to vars previously bound in the let*.

The form

 (let* ((var1 init-form-1)
        (var2 init-form-2)
        ...
        (varm init-form-m))
   declaration1
   declaration2
   ...
   declarationp
   form1
   form2
   ...
   formn)
first evaluates the expression init-form-1, then binds the variable var1 to that value; then it evaluates init-form-2 and binds var2, and so on. The expressions formj are then evaluated in order; the values of all but the last are discarded (that is, the body of let* is an implicit progn).

For both let and let*, if there is not an init-form associated with a var, var is initialized to nil.

The special form let has the property that the scope of the name binding does not include any initial value form. For let*, a variable's scope also includes the remaining initial value forms for subsequent variable bindings.

Examples:

 (setq a 'top) =>  TOP
 (defun dummy-function () a) =>  DUMMY-FUNCTION
 (let ((a 'inside) (b a))
    (format nil "~S ~S ~S" a b (dummy-function))) =>  "INSIDE TOP TOP" 
 (let* ((a 'inside) (b a))
    (format nil "~S ~S ~S" a b (dummy-function))) =>  "INSIDE INSIDE TOP" 
 (let ((a 'inside) (b a))
    (declare (special a))
    (format nil "~S ~S ~S" a b (dummy-function))) =>  "INSIDE TOP INSIDE"

The code

 (let (x)
   (declare (integer x))
   (setq x (gcd y z))
   ...)
is incorrect; although x is indeed set before it is used, and is set to a value of the declared type integer, nevertheless x initially takes on the value nil in violation of the type declaration.

Affected By: None.

Exceptional Situations: None.

See Also:

progv

Notes: None.


The following X3J13 cleanup issues, not part of the specification, apply to this section:


[Starting Points][Contents][Index][Symbols][Glossary][Issues]
Copyright 1996-2005, LispWorks Ltd. All rights reserved.

--------------000405000507010404030802 Content-Type: text/html; charset=ISO-8859-1; name="26_glo_b.htm" Content-Transfer-Encoding: quoted-printable Content-ID: Content-Disposition: inline; filename="26_glo_b.htm" CLHS: Glossary-Section B

3D"[LISPWORKS]"3D"[Common 3D"[Previous]"= 3D"[Up]=3D"[Next]"


B

backquote n. the standard character= that is variously called ``grave accent'' or ``backquote'' (`). See Figure 2-5<= /A>.

backslash n. the standard character= that is variously called ``reverse solidus'' or ``backslash'' (\= ). See Figure 2= -5.

base character n. a character of <= A REL=3DDEFINITION HREF=3D"26_glo_t.htm#type">type base-char.

base string n. a string of type base-string.

before method n. a method having the qualifier = :before.

bidirectional adj. (of a <= A REL=3DDEFINITION HREF=3D"26_glo_s.htm#stream">stream) being = both an input = stream and an= output stream.

binary adj. 1. (of a stream) being a stream that has an element type that is a subtype= of type integer. T= he most fundamental operation on a <= I>binary input= stream is read-byte= and on a binary output stream is write-byte. See character. 2. (of a= file) having b= een created by opening a binary stream= =2E (It is implementation-dependent whether this is an detectable as= pect of the file, or whether any given character file can be treated as a binary file.)

bind v.t. (a variable) to establish a binding for the variable.

binding n. an association betwee= n a name and th= at which the name denotes. ``A lexical binding is a lexical association between a name a= nd its value.'' When the term bi= nding is qualified by the name of a namespace, such as ``variable'' or ``fu= nction,'' it restricts the binding to the indicated namespace, as in: ``<= A REL=3DDEFINITION HREF=3D"s_let_l.htm#let">let establishes va= riable bindings.'' or ``l= et establishes bindings of variables.''

bit n. an object of type bit; that is, the integer 0 or the integer 1.

bit array n. a specialized array that is of = type (array= bit), and whose elements are of type bit.

bit vector n. a specialized <= A REL=3DDEFINITION HREF=3D"26_glo_v.htm#vector">vector that is= of type bit-vector, and= whose elements are of = type bit. <= P>

bit-wise logical o= peration specifier n. an object which names one of the sixteen possible= bit-wise logical operations that can be performed by the boole function, and which is t= he value of ex= actly one of the constant variables boole-clr, boole-set, boole-1, boole-2, boole-c1, boole-c2, = boole-and, = boole-ior, = boole-xor, = boole-eqv, boole-nand, boole-nor, boole-andc1, boole-andc2, boole-orc1, or boole-orc2.

block n. a named lexical exit point, est= ablished explicitly by block or implicitly by operators such as loop, do and prog= , to which control and values may be transfered by using a return-from form with the nam= e of the block.

block tag n. the symbol that, within the lexical scope of a block form, names t= he block established by that block= form. See return or return-from.

boa lambda list n. a lambda list= that is syntactically like an ordinary lambda list, but that is process= ed in ``by order of argument'' style. See Section 3.4.6 (Boa Lambda Lists).

body parameter n. a parameter avail= able in certain = lambda lists which from the point of view of conforming programs i= s like a rest= parameter in every way except that it is introduced by &= body instead of &rest. (Implementations are permitted to pro= vide extensions which distinguish body parameters and rest parameters---e.g., the forms for operators which were define= d using a body parameter<= /I> might be pretty printed slightly differently than forms for operators which were defined us= ing rest para= meters.)

boolean n. an object of type boolean; that is, one of the following objects: the symbol t (representing true), or the symbol nil (representing false). See generalized bo= olean.

boolean equivalent n.= (of an object O1) any object<= /A> O2 that has the same truth value as O1 when both O1 and O2 are viewed= as gene= ralized booleans.

bound adj., v.t. 1. adj.= having an associated denotation in a binding. ``The variables named by a let are bound within its body.'' See= unbound. 2.= adj. having a local bind= ing which sha= dows[2] another. ``The variable *print-escape* is bound while in the= princ function= =2E'' 3. v.t. the past tense of bind.

bound declaration n. a= declaration= that refers to or is associated with a variable or function and that appears within the special form<= /A> that establish= es the vari= able or fun= ction, but before the body of that special form (specifically, at the he= ad of that form= 's body). (If a bound = declaration refers to a function bi= nding or a lexical variable binding, the = scope of the declaration is exactly the scope of that binding. If the declaration refers to a dynamic variable binding, the scope of the declaration is what the scope of the binding would have been if it were l= exical rather than dynamic.)

bounded adj. (of a sequence S, by an ordere= d pair of bounding indices istart and iend) restricted to a subran= ge of the elements of S that includes each element beginning with (and including) the one indexed= by istart and continuing up to (but not including) the one indexed by ie= nd.

bounding index n. (of a <= A REL=3DDEFINITION HREF=3D"26_glo_s.htm#sequence">sequence wit= h length n) e= ither of a conceptual pair of integers, istart and iend, respectively called the ``lo= wer bounding index'' and ``upper bounding index'', such that 0 <=3Dist= art <=3Diend <=3Dn, and which therefore delimit a subrange of the <= A REL=3DDEFINITION HREF=3D"26_glo_s.htm#sequence">sequence bounded by istart and iend.=

bounding index designator= (for a sequenc= e) one of two objects that, taken together as an ordered pair, behave as a designator f= or bounding indices of the sequence; that is, they denote bounding indices= of the sequenc= e, and are either: an integer (denoting itself) and nil (denoting the length of the sequence), or two integers (each denoting themselv= es).

break loop n. A variant of th= e normal Lisp read-eval-print loop that is recursively entered, usu= ally because the ongoing evaluation of some other form has been suspended for the purpose of debu= gging. Often, a break loop provides the ability to exit in such a way as to continue the suspe= nded computation. See the function break.

broadcast stream n. an = output stream of type broadcast-stream.

built-in class n. a class that is a generalize= d instance of = class built-in-class.

built-in type n. one of th= e types in Figure 4-2= .

byte n. 1. adjacent bits within an = integer. (Th= e specific number of bits can vary from point to point in the program; se= e the function<= /A> byte.) 2. an= integer in a specified range. (The specific range can vary from point to= point in the program; see the functions open and write-byte.)

byte specifier n. An object of implementati= on-dependent nature that is returned by the function byte and that specifies the range of bi= ts in an integer= to be used as a byte b= y functions= such as ldb.


The following X3J13 c= leanup issue, not part of the specification, applies to this s= ection:


3D"[Starting3D"[Contents]"3D"[Index]"3D=3D"[Issues]"
Copyright 1996-200= 5, LispWorks Ltd. All rights reserved.

--------------000405000507010404030802--