All Projects → kristianlm → chicken-gochan

kristianlm / chicken-gochan

Licence: other
Go-like Channels for Chicken Scheme

Programming Languages

scheme
763 projects

Projects that are alternatives of or similar to chicken-gochan

Javamtp
《Java多线程编程实战指南(设计模式篇)》源码
Stars: ✭ 575 (+3094.44%)
Mutual labels:  multi-threading, concurrency
Thread Pool
Thread pool implementation using c++11 threads
Stars: ✭ 417 (+2216.67%)
Mutual labels:  multi-threading, concurrency
thread-pool
BS::thread_pool: a fast, lightweight, and easy-to-use C++17 thread pool library
Stars: ✭ 1,043 (+5694.44%)
Mutual labels:  multi-threading, concurrency
Hamsters.js
100% Vanilla Javascript Multithreading & Parallel Execution Library
Stars: ✭ 517 (+2772.22%)
Mutual labels:  multi-threading, concurrency
Fucking Java Concurrency
🎏 Simple show cases of java concurrency problems, seeing 🙈 is believing 🐵
Stars: ✭ 779 (+4227.78%)
Mutual labels:  multi-threading, concurrency
Overdrive
⚡️ Fast async task based Swift framework with focus on type safety, concurrency and multi threading
Stars: ✭ 823 (+4472.22%)
Mutual labels:  multi-threading, concurrency
TAOMP
《多处理器编程的艺术》一书中的示例代码实现,带有注释与单元测试
Stars: ✭ 39 (+116.67%)
Mutual labels:  multi-threading, concurrency
psched
Priority-based Task Scheduling for Modern C++
Stars: ✭ 59 (+227.78%)
Mutual labels:  concurrency
Paraphrase
Multi-core suitable Forth-like language
Stars: ✭ 27 (+50%)
Mutual labels:  multi-threading
fork-helper
A PHP helper to fork processes and allow multi-threading
Stars: ✭ 69 (+283.33%)
Mutual labels:  multi-threading
queueable
Convert streams to async ⌛ iterables ➰
Stars: ✭ 43 (+138.89%)
Mutual labels:  concurrency
go-stm
Software Transactional Memory for Go
Stars: ✭ 15 (-16.67%)
Mutual labels:  concurrency
gotopus
Gotopus is a minimalistic tool that runs arbitrary commands concurrently.
Stars: ✭ 17 (-5.56%)
Mutual labels:  concurrency
edd
Erlang Declarative Debugger
Stars: ✭ 20 (+11.11%)
Mutual labels:  concurrency
piker
#nontina, #paperhands,, #pwnzebotz, #tradezbyguille
Stars: ✭ 63 (+250%)
Mutual labels:  concurrency
channel
Go-like channels for JavaScript
Stars: ✭ 49 (+172.22%)
Mutual labels:  concurrency
rethinkdb.nim
RethinkDB driver for Nim
Stars: ✭ 35 (+94.44%)
Mutual labels:  multi-threading
gpool
gpool - a generic context-aware resizable goroutines pool to bound concurrency based on semaphore.
Stars: ✭ 84 (+366.67%)
Mutual labels:  concurrency
geeteventbus
An inprocess eventbus for highly concurrent Python applications
Stars: ✭ 17 (-5.56%)
Mutual labels:  concurrency
ring-election
A node js library with a distributed leader/follower algorithm ready to be used
Stars: ✭ 92 (+411.11%)
Mutual labels:  concurrency

chicken-gochan

Go-inspired channels for Chicken Scheme (Chibi Scheme might work too). Essentially thread-safe fifo queues that are useful for thread communication and synchronization.

Dependencies

Development Status

Currently supported:

  • receive and send switch (gochan-select)
  • buffered channels
  • timeouts as ordinary receive on a channel
  • closable channels with close-reason (aka fail-flag)
  • load-balancing when multiple channels have data ready

Source code can be found here.

Comparison to real Go Channels

The API and behaviour largely follows Go's channel API, with some exceptions:

  • channels don't have any type information
  • sending to a channel that gets closed does not panic, it unblocks all senders immediately with the fail flag set to non-#f.
  • closing an already closed channel does not result in error.
  • nil-channels aren't supported, create new forever-blocking (gochan 0) instead.
  • Unlike in Go, you can choose what channels to select on at runtime with gochan-select*

Comparison to core.async

Honestly, I wish I had stolen the core.async API instead of the Go channel API since that's already a LISP, but here is what we have for now:

  • alt! is gochan-select
  • alts! is gochan-select*
  • <! is gochan-recv
  • >! is gochan-send
  • There is no distinction between park and block because CHICKEN doesn't have native threads.
  • The operations don't need to be called inside (go ...) blocks.

API

[procedure] (gochan capacity)

Construct a channel with a maximum buffer-size of capacity. If capacity is 0, the channel is unbuffered and all its operations will block until a remote end sends/receives.

[procedure] (gochan-select ((chan <-|-> msg [ fail ]) body ...) ... [(else body ...])

This is a channel switch that will send or receive on a single channel, picking whichever clause is able to complete soonest. If no clause is ready, gochan-select will block until one does, unless else is specified which will by execute its body instead of blocking. Multiple send and receive clauses can be specified interchangeably. Note that only one clause will be served.

Here's an example:

(gochan-select
  ((chan1 -> msg fail) (if fail (print "chan1 closed!") (print "chan1 says " msg)))
  ((chan2 -> msg fail) (if fail (print "chan2 closed!") (print "chan2 says " msg))))

Receive clauses, ((chan -> msg [fail]) body ...), execute body with msg bound to the message object and fail bound to a flag indicating failure. Receiving from a closed channel immediately completes with this fail flag set to non-#f.

Send clauses, ((chan <- msg [fail]) body ...), execute body after msg has been sent to a receiver, successfully buffered onto the channel, or if channel was closed. Sending to a closed channel immediately completes with the fail flag set to #f.

A send or receive clause on a closed channel with no fail-flag binding specified will immediately return (void) without executing body. This can be combined with recursion like this:

;; loop forever until either chan1 or chan2 closes
(let loop ()
   (gochan-select
    ((chan1 -> msg) (print "chan1 says " msg) (loop))
    ((chan2 <- 123) (print "chan2 got  " 123) (loop))))

Or like this:

;; loop forever until chan1 closes. replacing chan2 is important to avoid busy-wait!
(let loop ((chan2 chan2))
  (gochan-select
   ((chan1 -> msg)      (print "chan1 says " msg) (loop chan2))
   ((chan2 -> msg fail) (if fail
                            (begin (print "chan2 closed, keep going")
                                   ;; create new forever-blocking channel
                                   (loop (gochan 0)))
                            (begin (print "chan2 says " msg)
                                   (loop chan2))))))

gochan-select returns the return-value of the executed clause's body.

To do a non-blocking receive, you can do the following:

(gochan-select ((chan1 -> msg fail) (if fail #!eof msg))
               (else 'eagain))
[procedure] (gochan-send chan msg)

This is short for (gochan-select ((chan <- msg fail) (values #f fail #t))).

[procedure] (gochan-recv chan)

This is short for (gochan-select ((chan -> msg fail) (values msg fail #t))).

[procedure] (gochan-close chan [fail-flag])

Close the channel. Note that this will unblock existing receivers and senders waiting for an operation on chan with the fail-flag set to a non-#f value. All future receivers and senders will also immdiately unblock in this way, so watch out for busy-loops.

The optional fail-flag can be used to specify an alternative to the default #t. As this value is given to all receivers and senders of chan, the fail-flag can be used as a "broadcast" mechanism. fail-flag cannot be #f as that would indicate a successful message transaction.

Closing an already closed channel will results in its fail-flag being updated.

[procedure] (gochan-after duration/ms)

Returns a gochan that will "send" a single message after duration/ms milliseconds of its creation. The message is the (current-milliseconds) value at the time of the timeout (not when the message was received). After the timeout message has been delivered once, subsequent receives will immediately report the channel as closed.

(gochan-select
 ((chan1 -> msg)                (print "chan1 says " msg))
 (((gochan-after 1000) -> when) (print "chan1 took too long")))

You cannot send to or close a timer channel. These are special records that contain information about when the next timer will trigger. Creating timers is a relatively cheap operation, and unlike golang.time.After, may be garbage-collected before the timer triggers. Creating a timer does not spawn a new thread.

[procedure] (gochan-tick duration/ms)

Return a gochan that will "send" a message every duration/ms milliseconds. The message is the (current-milliseconds) value at the time of the tick (not when it was received).

See tests/worker-pool.scm for an example of its use.

[procedure] (go body ...)

Starts and returns a new srfi-18 thread. Short for (thread-start! (lambda () body ...)).

Samples

TODO

  • Perhaps rename the API to core.async's?
  • Add go-map, go-fold and friends (hopefully simple because we can also do this)
  • Support customizing buffering behaviour, like core.async's dropping-buffer and sliding-buffer (harder!)
  • Add a priority option to gochan-select*?
  • Add possibility to block until channel is closed without touching channel data
  • Support cancelling timers
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].