C# .NET中的Erlang风格轻量级进程
有没有办法在.NET中实现Erlang风格的轻量级进程C# .NET中的Erlang风格轻量级进程,c#,.net,concurrency,erlang,lightweight-processes,C#,.net,Concurrency,Erlang,Lightweight Processes,有没有办法在.NET中实现Erlang风格的轻量级进程 我发现了一些实现Erlang消息传递模型(actors模型)的项目。例如但是我没有发现关于轻量级流程的任何内容。我指的是在单个操作系统线程或操作系统进程的上下文中运行的多个进程。这毫无意义。“在单个OS线程或OS进程的上下文中运行的多个进程”在逻辑上是不确定的。这基本上是一个逻辑应用程序级的东西-你可以很容易地在.NET中重新编程。但是在操作系统级别上没有“进程中的进程”这样的东西。可以托管CLR,并公开主机实现其自身任务抽象的机制。从理论
我发现了一些实现Erlang消息传递模型(actors模型)的项目。例如但是我没有发现关于轻量级流程的任何内容。我指的是在单个操作系统线程或操作系统进程的上下文中运行的多个进程。这毫无意义。“在单个OS线程或OS进程的上下文中运行的多个进程”在逻辑上是不确定的。这基本上是一个逻辑应用程序级的东西-你可以很容易地在.NET中重新编程。但是在操作系统级别上没有“进程中的进程”这样的东西。可以托管CLR,并公开主机实现其自身任务抽象的机制。从理论上讲,它们可以是线程、光纤、LWP—只要主机实现这些功能,它们都可以是 要做到这一点有些困难。MS利用这个机会以SQL Server光纤模式托管CLR 在最后一刻,出现了一些压力bug,因此他们根据and(谁运行了一个)的说法停止了它。
现在缺少了一些管道——即使人们能够绕过它,在压力测试迭代中击中MS的同样的错误也可能会困扰冒险的灵魂 假设所有问题都以某种方式得到解决,整个运行时准备在光纤、LWP等设备上运行。仍然存在P/Invoke的问题,它可能会调用阻塞操作。如果没有内核支持,这种调度很难实现 64位版本的Windows 7和Windows 2008 Server R2解决了这一问题。如果调用在内核中阻塞,现在有一个调度程序可以将控制权返回到用户模式(与内核模式相反)调度器。此外,这些用户模式调度线程是具有自己TLS的真实线程。这些都是巨大的改进,并使许多光纤模式的头痛消失 现在,就在那一刻。
后者意味着您可以使用它的开箱即用 你看过吗?我只是读过,但我什么也没做,但…我想你要找的是F#MailboxProcessor Alexey。使用MailboxProcessor,您可以在一个.NET进程中定义数万个代理,就像您可以在Erlang中生成数万个轻量级进程一样 唐·赛姆的这篇文章是一个很好的介绍
如果您是从Erlang后台来到.NET的,请记住,您将丢失很多OTP功能(管理器、位置透明性、mnesia等等)。Erlang进程类似于并行运行方法,但Erlang变量只能绑定一次,因此它是线程安全的,而不是c# 因此,在c#中需要两件事,线程安全和并行 C#具有System.Threading.Task,您可以在vm中运行许多任务。C#vm将在不同的工作线程中调度这些任务 但任务不是线程安全的,您需要创建一个名为Actor的类,并将stateprivate放在Actor中 参与者有一个System.Threading.SynchronizationContext和许多异步方法,如下所示
class Actor {
public SynchronizationContext _context;
private int value1;
private Dictionary<> xxx;
private List<> xxx;
public async Task Method1() {
await _context;
doSomething();
}
}
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(){}
}
公共密封类同步ContextWaiter:INotifyCompletion
{
私有只读同步上下文\u上下文;
公共SynchronizationContextWaiter(SynchronizationContext上下文)
{
如果(context==null)抛出新的ArgumentNullException(“context”);
_上下文=上下文;
}
公共图书馆完工了{
得到
{
//已经在当前上下文里面了,就不需要再次切换上下文
返回SynchronizationContext.Current==\U上下文;
}
}
///
/// 将行动任务调度到 _上下文控制的线程里面去执行
///
///var temp=e.GetAwaiter();
///
///行动。
未完成公共作废(行动){
_Post(x=>action(),null);
}
public void GetResult(){}
}
然后您会得到一个Actor类,它具有任务和线程安全,就像erlang中的进程一样。“进程中的进程”-Win32有一个光纤。但是光纤是自调度的-线程(在大多数情况下没有意义)。一个进程被定义为具有一个光纤所缺少的内存屏障。因此,光纤绝不是进程中的进程,您显然没有看过Erlang的运行时设计。是的,您可以在应用程序级别实现类似于Erlang的进程,但这可能相当于协作多任务处理,这是我在DOS/Win16之后从未见过的一种技术。如果您在运行时有支持,您可以通过抢占式多任务处理获得这种效果,但这将是MS必须添加到.NET中的内容。请看一看,如果您将其使用限制在F#或其他函数式语言中,这些功能会消失吗,为了避免一个进程破坏另一个进程的存储而带来的一些困难?@Warren:这里的任务管理并不真正关心防止一个线程/光纤/LWP写入另一个进程的内存。毕竟,这是一种预期行为——每次启动多线程程序时都会这样做——所有线程都会访问并共享进程的内存。@Warren:……话虽如此,避免或最小化共享状态是提高并行性的好方法之一。它也可以用C#来完成——尽管该语言没有强制执行或特别鼓励它。假设OP没有专注于某一特定语言,那么这很有用。将对Axum的任何引用解释为“呜呜!什么都行,宝贝!”通常不是安全的吗
public static class SynchroniztionContextExtensions
{
public static SynchronizationContextAwaiter GetAwaiter (this SynchronizationContext context)
{
if(context == null) throw new ArgumentNullException("context");
return new SynchronizationContextAwaiter(context);
}
}
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(){}
}