Skip to content

garlic0x1/cl-workers

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cl-workers

Intro

This is based on cl-actors, the basic API can be used similarly, but there are some differences and more high level features. It uses a thread-safe queue as a mailbox and actors run on bordeaux-threads.

Examples

Create a global stateful worker

;;                name     state   args
(defworker/global :counter ((i 0)) (increment)
  (sleep 1)                ; simulate work
  (setf i (+ i increment)) ; increment state
  (print i)                ; print new value
  )

(send :counter 1) ; prints 1 after 1 second
(send :counter 4) ; prints 5 after 2 seconds

;; a hashmap of the workers is available
(gethash :counter *global-workers*)
;;> #<CL-WORKERS/TYPES:WORKER {1002E3E293}>

;; convenience macro to close workers and wait for them to end
(close-and-join-workers :counter)

Factorial

Joining a worker returns the value its body last returned, so we can get the result of a computation like this:

(defworker/global :fac () (x ag)
  (if (= x 0)
      (progn (close-worker self) ag) ; store the result
      (send self (- x 1) (* x ag))))
(send :fac 4 1)
(join-worker :fac)
24

cl-actors style definition

defworker binds ,name to a function that creates the specified workers

(defworker nagger () ()
  (sleep 1)
  (print "hi")
  (send self)  ; message itself, infinite loop
  )

;; anonymous actor , no way to stop the nagging
(send (nagger))

&rest

Refer to t/cl-workers-test.lisp for more examples

Functional differences between cl-workers and cl-actors

No need to return the next behavior

This annoyed me as I generally will just return the current behavior, if you need something like this, you can just keep a lambda in the worker state or mutate the worker’s behav slot.

Closing mailboxes

This works similarly to Golang channels, when a worker recieves a close-signal, it stops working and the thread finishes. This allows other threads to wait for workers.

Global workers

defworker/global constructs a global singleton worker that can be accessed by its keyword name, this is handy for defining rate limiters and other jobs that should only have one worker

Improvement ideas

Naming

defworker and defworker/global could be one macro handling worker and keyword differently, but I think having them separate might be more clear for users.

Supervisors

I will hopefully add this after experiementing with it independent of this library.

It might be necessary to allow spawning a worker instance to give it some kind of unique ID for the supervisor to recognize it.

About

Actor library for Common Lisp

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published