8

I started playing with the Actor model, and in particular with Akka.NET. Overall I think I have a good idea of what's all about, but of course the devil is in the detail. I was thinking about adopting Akka.NET in an already existing codebase, and therefore I'd like to estimate how much of the existing abstractions can be kept. The idea is that some specific high-level interfaces could be kept, and some adapter implementations would be written to seamlessly go back and forth across the actors world and the users of the existing interfaces, but I'm not sure if that's recommended and what types of specific problems I should expect to face.

Trivial example:

public interface IGetSet<in TK, TV>
{
    TV Get(TK key);
    void Set(TK key, TV value);
}

public class GetSet<TK, TV> : IGetSet<TK, TV>
{
    private readonly ActorRef _getSetActor;

    public GetSet(ActorRefFactory system)
    {
        _getSetActor = system.ActorOf(Props.Create(() => new GetSetActor()));
    }

    public TV Get(TK key)
    {
        var x =  _getSetActor.Ask<TV>(new GetSetActor.Get(key));
        return x.Result;  //blocking, I know, it's just an example
    }

    public void Set(TK key, TV value)
    {
        _getSetActor.Tell(new GetSetActor.Set(key, value));
    }

    class GetSetActor : ReceiveActor
    {
        readonly Dictionary<TK, TV> _values = new Dictionary<TK, TV>();

        public class Get
        {
            public Get(TK key) { Key = key; }
            public TK Key { get; private set; }
        }

        public class Set
        {
            public Set(TK key, TV value) { Key = key; Value = value; }
            public TK Key { get; private set; }
            public TV Value { get; private set; }
        }

        public GetSetActor()
        {
            Receive<Get>(g => Sender.Tell(_values[g.Key], Self));
            Receive<Set>(g => _values[g.Key] = g.Value);
        }
    }
}

...

var gs = new GetSet<string, int>(ActorSystem.Create("Wasp"));
gs.Set("a", 42);
var i = gs.Get("a");

In this case the IGetSet interface comes from the traditional world, and its implementation lets us transition back and forth with the actors world. I tried to be nice with actors, which are never used in ways different from message passing, so overall this (trivial, of course) exercise looks promising, but I'd like to know if there's anything more I should pay attention to since day 1.

I've been reading about avoiding additional non-actor-based async code taking closures on actors' state, that's clear and I'm not doing it, but maybe there's more which I can't see. My final goal is to use this pattern quite extensively, down to point I'd write actor-oriented implementations of Rx's ISubject (which BTW I already did and it was easy, but again I'm not sure I paid enough attention to all I should).

I also read a bit about Typed Actors, but I'm not a Scala expert so maybe I'm not grasping all the details from the code samples, and I'm not sure they are already available within Akka.NET (doc page is a 404)

4

1 回答 1

7

这看起来不错。您应该考虑的是,默认情况下,演员有“最多一次”的交付保证,因此,您应该考虑到在与您的演员沟通时,您可能不会得到回复。(网络故障、远程节点崩溃等)

在本地系统中,消息丢失的可能性很小,但理论上,如果有人对它进行过于疯狂的操作,则参与者系统可能会崩溃,从而导致参与者死亡。

因此,当与参与者通信时,使用Ask更好的是安全并提供超时并处理该异常,而不是永远阻塞/等待。

从最新的预发布位(1.0 之前)开始支持 Async/Await。然而,这不是推荐的方法。最好坚持PipeTo并明确。

另一件事可能会变得不确定,因为在您的示例中,您将演员视为键值存储,这一切都很好。而且您的消息也是不可变的,这也很好。但是如果 Key 或 Value 属性是 ref 类型,并且人们可以从外部改变它们,例如,它的消费者IGetSet可能会在 actor 内部导致 RC 问题,因为当另一个线程正在改变它们时,actor 可能会读取这些值。

ActorSystems也相当昂贵,尽量避免启动多个系统,每个进程的目标是一个系统。

除此之外,你很高兴。

于 2015-04-06T18:33:03.657 回答