Select in Lisp

Common Lisp doesn’t have built-in support for concurrent programming like Go’s goroutines and channels. However, we can use threads and queues to achieve similar functionality. Here’s an example that mimics the behavior of the original Go code:

(ql:quickload '(:bordeaux-threads :cl-cont))

(defpackage :select-example
  (:use :cl :bordeaux-threads :cl-cont))

(in-package :select-example)

(defun main ()
  ;; For our example we'll select across two queues.
  (let ((q1 (make-queue))
        (q2 (make-queue)))

    ;; Each queue will receive a value after some amount
    ;; of time, to simulate e.g. blocking operations
    ;; executing in concurrent threads.
    (make-thread
     (lambda ()
       (sleep 1)
       (enqueue "one" q1)))
    
    (make-thread
     (lambda ()
       (sleep 2)
       (enqueue "two" q2)))

    ;; We'll use a loop to await both of these values
    ;; simultaneously, printing each one as it arrives.
    (dotimes (i 2)
      (select
        ((dequeue q1) (msg)
         (format t "received ~a~%" msg))
        ((dequeue q2) (msg)
         (format t "received ~a~%" msg))))))

(defun run-example ()
  (time (main)))

;; Run the example
(run-example)

In this Lisp version:

  1. We use the bordeaux-threads library for thread creation and the cl-cont library for the select macro, which provides functionality similar to Go’s select.

  2. We define two queues q1 and q2 instead of channels.

  3. We create two threads that sleep for 1 and 2 seconds respectively, then enqueue values to the queues.

  4. We use a dotimes loop to dequeue values from both queues, similar to the for loop in the Go version.

  5. The select macro is used to wait on both queues simultaneously, printing each value as it arrives.

To run this program, you would typically save it to a file (e.g., select-example.lisp) and load it into your Lisp environment. The output would be similar to:

Evaluation took:
  2.002 seconds of real time
  0.000078 seconds of total run time (0.000078 user, 0.000000 system)
  0.00% CPU
  5,662,627,592 processor cycles
  32,768 bytes consed
  
received one
received two

Note that the total execution time is only about 2 seconds since both the 1 and 2 second sleeps execute concurrently.

This example demonstrates how to implement concurrent operations and selection between multiple sources in Common Lisp, achieving functionality similar to Go’s select statement and goroutines.