开发者

Erlang-style light-weight processes in .NET

Is there any way to implement Erlang-style light-weight processes in .NET?

I found some projects that implement Erlang messaging model (actors model). For example, Axum. But I found nothing about light-weight processes implementation. I mean multiple processes that run in 开发者_运维百科a context of a single OS-thread or OS-process.


I think the F# MailboxProcessor is what you're looking for Alexey. Using the MailboxProcessor you can define tens of thousands of agents within one .NET process much like you can spawn tens of thousands of lightweight processes in Erlang.

This MSDN post by Don Syme is a great introduction.

If you're coming to .NET from an Erlang background keep in mind you're going to be missing lots of OTP goodies (supervisors, location transparency, mnesia, ...).


The CLR can be hosted and exposes mechanisms for the host to implement its own task abstraction. Theoretically, they can be threads, fibers, LWPs - anything as long as the host implements the necessary interfaces.

Getting it right is somewhat hard. MS took a chance on it in order to host the CLR in SQL Server Fiber Mode.

At the last moment, there were some stress bugs, so they pulled the plug on it according to Joe Duffy and Dino Vhieland (who ran a series about writing a custom CLR host that implements its own task abstraction - with fibers - on his blog).
Right now there is some plumbing missing - ICLRTask::SwitchOut() - and even if one gets around that, the same bugs that hit MS at the stress test iteration would probably haunt the adventurous soul as well.

Suppose for a moment that all the problems are somehow fixed and the whole runtime is prepared to run on fibers, LWPs, whatever. There is still the problem of P/Invoke that might potentially call into blocking operations. This kind of scheduling is hard to do without kernel support.

This is addressed in the 64bit versions of Windows 7 and Windows 2008 Server R2. There is now User-Mode Scheduling that can yield control back to a user-mode - as opposed to kernel-mode - scheduler if a call blocks in the kernel. Also, these user-mode scheduled threads are real threads with their own TLS. These are great improvements and make many of the fiber mode headaches go away.

Right now, UMS is utilized in the Concurrency Runtime that is available for C++ and is part of the C Runtime Library (CRT).
The latter means that you can use it out of the box with Visual Studio 2010.


Have You had a look at retlang? I only read about it, but I didn't do anything with it, yet...


Erlang process is like running method parallelly, but erlang variable can only be bound once, so it is thread safe which is not in c#.

so you need two things in c#, thread safe and parallel.

C# has System.Threading.Task, you can run many tasks in vm. C# vm will scheduler these task in different working threads.

But task is not thread safe, you need to make a class called Actor, and put state private in the Actor.

The Actor has a System.Threading.SynchronizationContext, and many async Methods, like this.

class Actor {
  public SynchronizationContext _context;

  private int value1;
  private Dictionary<> xxx;
  private List<> xxx;


  public async Task Method1() {
      await _context;

      doSomething();
  }

}

When other Actors call the async method in this Actor, it will create a task, and the task will scheduled by vm.

You also need to implement a awaitable and thread safe SynchronizationContext.

this is a thread safe context.

public class ActorSynchronizationContext : SynchronizationContext
{
    private readonly SynchronizationContext _subContext;
    private readonly ConcurrentQueue<Action> _pending = new ConcurrentQueue<Action>();
    private int _pendingCount;

    public ActorSynchronizationContext(SynchronizationContext context = null)
    {
        this._subContext = context ?? new SynchronizationContext();
    }

    public override void Post(SendOrPostCallback d, object state)
    {
        if (d == null) {
            throw new ArgumentNullException("SendOrPostCallback");
        }
        _pending.Enqueue(() => d(state));
        if (Interlocked.Increment(ref _pendingCount) == 1)
        {
            try
            {
                _subContext.Post(Consume, null); 
            }
            catch (Exception exp)
            {
                LogHelper.LogUnhandleException(exp.ToString());
            }
        }
    }

    private void Consume(object state)
    {
        var surroundContext = Current;
        SetSynchronizationContext(this);
        do
        {
            Action a;
            _pending.TryDequeue(out a);
            try
            {
                a.Invoke();
            }
            catch (Exception exp)
            {
                //Debug.LogError(exp.ToString());
                LogHelper.LogUnhandleException(exp.ToString());
            }
        } while (Interlocked.Decrement(ref _pendingCount) > 0);
        SetSynchronizationContext(surroundContext);
    }

    public override void Send(SendOrPostCallback d, object state)
    {
        throw new NotSupportedException();
    }
    public override SynchronizationContext CreateCopy()
    {
        return this;
    }
}

make SynchroniztionContext awaitable

public static class SynchroniztionContextExtensions
{
    public static SynchronizationContextAwaiter GetAwaiter (this   SynchronizationContext context) 
    {
        if(context == null) throw new ArgumentNullException("context");
        return new SynchronizationContextAwaiter(context);
    }
}

Awaiter for SynchronizationContext

public sealed class SynchronizationContextAwaiter : INotifyCompletion
{
    private readonly SynchronizationContext _context;
    public SynchronizationContextAwaiter(SynchronizationContext context)
    {
        if(context == null ) throw new ArgumentNullException("context");
        _context = context;
    }
    public bool IsCompleted {
        get
        {
            //已经在当前上下文里面了,就不需要再次切换上下文
            return SynchronizationContext.Current == _context;
        }
    }

    /// <summary>
    /// 将Action 任务调度到 _context 控制的线程里面去执行
    /// 
    /// var temp = e.GetAwaiter();
    /// </summary>
    /// <param name="action">Action.</param>
    public void OnCompleted(Action action) {
        _context.Post(x=>action(), null);
    }
    public void GetResult(){}
} 

then you get an Actor class with task and thread safe which like process in erlang.


This makes no sense. "Multiple process that run in the context of a single OS thread or OS process" is logically inconclusive. THis is basically a logical application level thing - which you can easily repro in .NET. But there is no such thing like a "process within a process" on the OS level.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜