As a newcomer, I decided to try and write a small actor library as an excuse to learn Nim. It does need more work, especially on the scheduler, but I'd love feedback from the community. This is definitely something I might want to use in the future.
https://github.com/evacchi/nimoy
Share your thoughts, feel free to PR.
I think it's too early right now, it really is a handful of lines of code; but I probably will if there is enough interest.
RIght now, actors run on a thread pool (not Nim's threadpool) that can be configured.
The execution strategy and migration of an actor across threads is pretty dumb, but it's pluggable. Any contribution in this regard would be welcome.
My idea (not implemented right now) is to keep actors on the same thread unless some condition is not met (to limit copying). Messaging uses channels.
news: featuring super-experimental support for actor topologies
import future, nimoy, nimoy/topologies
#
# source ~> map1 ~> fanIn ~> map3 ~> broadcast ~> sink1
# +~~~~> map2 ~~~~~^ +~~~~> sink2
#
let t = createTopology()
let sink1Ref = t.sinkRef((x: int) => echo("sink1 = ", x))
let sink2Ref = t.sinkRef((x: int) => echo("sink2 = ", x))
let bref = t.broadcastRef(sink1Ref, sink2Ref)
let map3Ref = t.nodeRef((x: int) => x+7, bref)
let fanInRef = t.nodeRef((x: int) => ( echo("fan in = ", x); x ), map3Ref)
let map2Ref = t.nodeRef((x: int) => x-1, fanInRef)
let map1Ref = t.nodeRef((x: int) => x*2, fanInRef)
# send input
for i in 0..10:
map1Ref ! i
t.awaitTermination()
news: no changes on the surface, a few internal changes. New API: support for "actor channels" a thin wrapper around shared channels
let t = createTopology()
let sink1 = allocActorChannel[int]()
let sink2 = allocActorChannel[int]()
# declare output sinks
let sink1Ref = t.sinkRef((x: int) => sink1.send(x*100))
let sink2Ref = t.sinkRef((x: int) => sink2.send(x))
# broadcast to both sinks
let bref = t.broadcastRef(sink1Ref, sink2Ref)
# map to the broadcast
let map3Ref = t.nodeRef((x: int) => x+7, bref)
# map to map3
let fanInRef = t.nodeRef((x: int) => ( echo("fan in = ", x); x ), map3Ref)
# two nodes that both go into fanIn
let map1Ref = t.nodeRef((x: int) => x*2, fanInRef)
let map2Ref = t.nodeRef((x: int) => x-1, fanInRef)
# send data to both the sources
for i in 0..10:
map1Ref ! i
map2Ref ! i
for i in 0..10:
echo sink1.recv()
echo sink2.recv()