c# .net concurrency erlang lightweight-processes

c# - Procesos livianos de estilo Erlang en.NET



concurrency lightweight-processes (5)

¿Hay alguna forma de implementar procesos livianos de estilo Erlang en .NET?

Encontré algunos proyectos que implementan el modelo de mensajería de Erlang (modelo de actores). Por ejemplo, Axum . Pero no encontré nada sobre la implementación de procesos livianos . Me refiero a múltiples procesos que se ejecutan en un contexto de un único subproceso del sistema operativo o proceso del sistema operativo.


¿Has echado un vistazo a retlang ? Solo leí al respecto, pero no hice nada con eso, aún ...


Creo que el F # MailboxProcessor es lo que estás buscando Alexey. Usando el MailboxProcessor puede definir decenas de miles de agentes en un proceso .NET de forma similar a como puede engendrar decenas de miles de procesos livianos en Erlang.

Esta publicación de MSDN por Don Syme es una gran introducción.

Si vienes a .NET desde un fondo de Erlang ten en cuenta que te faltarán muchos objetos de OTP (supervisores, transparencia de ubicación, mnesia, ...).


El CLR se puede alojar y expone los mecanismos para que el host implemente su propia abstracción de tareas. Teóricamente, pueden ser hilos, fibras, LWP, cualquier cosa, siempre que el host implemente las interfaces necesarias .

Hacer las cosas bien es algo difícil. MS se arriesgó para alojar el CLR en el modo de fibra de SQL Server.

En el último momento, hubo algunos errores de estrés, por lo que se detuvieron, según Joe Duffy y Dino Vhieland (que dirigió una serie sobre cómo escribir un servidor CLR personalizado que implementa su propia abstracción de tareas - con fibras - en su blog ) .
En este momento falta algo de fontanería - ICLRTask::SwitchOut() - e incluso si uno lo soluciona, los mismos errores que golpean a MS en la iteración de la prueba de estrés probablemente también acecharían al alma aventurera.

Supongamos por un momento que todos los problemas se arreglan de alguna manera y todo el tiempo de ejecución está preparado para funcionar con fibras, LWP, lo que sea. Todavía existe el problema de P / Invoke que podría llamar operaciones de bloqueo. Este tipo de programación es difícil de hacer sin compatibilidad con kernel.

Esto se aborda en las versiones de 64 bits de Windows 7 y Windows 2008 Server R2. Ahora hay Programación en Modo de Usuario que puede devolver el control a un modo de usuario , en oposición al modo de kernel, si la llamada se bloquea en el kernel. Además, estos subprocesos programados en modo de usuario son subprocesos reales con su propio TLS. Estas son grandes mejoras y hacen desaparecer muchos de los dolores de cabeza del modo de fibra.

En este momento, UMS se utiliza en el tiempo de ejecución de simultaneidad que está disponible para C ++ y es parte de la biblioteca de tiempo de ejecución de C (CRT) .
Esto último significa que puede usarlo de manera inmediata con Visual Studio 2010 .


El proceso de Erlang es como ejecutar el método en paralelo, pero la variable de erlang solo puede vincularse una vez, por lo que es segura para subprocesos y no está en c #.

entonces necesitas dos cosas en c #, hilo seguro y paralelo.

C # tiene System.Threading.Task, puede ejecutar muchas tareas en vm. C # vm programará estas tareas en diferentes hilos de trabajo.

Pero la tarea no es segura para subprocesos, debe crear una clase llamada Actor y poner el estado privado en el Actor.

El Actor tiene un System.Threading.SynchronizationContext y muchos métodos async, como este.

class Actor { public SynchronizationContext _context; private int value1; private Dictionary<> xxx; private List<> xxx; public async Task Method1() { await _context; doSomething(); } }

Cuando otros actores llaman al método async en este Actor, creará una tarea y la tarea será programada por vm.

También necesita implementar un SynchronizationContext que sea seguro y esté seguro para la ejecución de subprocesos.

este es un contexto seguro de subprocesos.

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; } }

hacer SynchroniztionContext a la espera

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

Awaiter para 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(){} }

luego obtienes una clase Actor con la tarea y el hilo seguro, que como proceso en erlang.


Esto no tiene sentido. "Múltiples procesos que se ejecutan en el contexto de un único proceso del sistema operativo o subproceso del sistema operativo" no es lógicamente concluyente. Esto es básicamente una cosa lógica de nivel de aplicación, que puedes repro fácilmente en .NET. Pero no hay tal cosa como un "proceso dentro de un proceso" en el nivel del sistema operativo.