2010-04-12 2 views
7

Есть ли способ реализовать легкие процессы Erlang в .NET?Легкие процессы в стиле Erlang в .NET.

Я нашел несколько проектов, которые реализуют модель обмена сообщениями Erlang (модель актеров). Например, Axum. Но я ничего не нашел о легких процессах реализации. Я имею в виду несколько процессов, которые выполняются в контексте одного OS-потока или OS-процесса.

ответ

10

Я думаю, что F # MailboxProcessor - это то, что вы ищете Алексея. Используя MailboxProcessor вы можете определить десятки тысяч агентов в рамках одного процесса .NET, так как вы можете создавать десятки тысяч легких процессов в Erlang.

Этот MSDN post от Don Syme - отличное введение.

Если вы идете на .NET с фона Erlang, имейте в виду, что вам не хватало много преимуществ OTP (супервизоры, прозрачность местоположения, mnesia, ...).

+0

Полезно, если OP не фокусируется на определенном языке. –

+0

Разве это не безопасно интерпретировать любую ссылку на Аксум как «Woohoo! Все идет, детка!» :) –

-2

Это не имеет никакого смысла. «Несколько процессов, которые выполняются в контексте одного потока ОС или процесса ОС», логически неубедительны. Это в основном логическая вещь уровня приложения, которую вы можете легко воспроизвести в .NET. Но нет такой вещи, как «процесс внутри процесса» на уровне ОС.

+2

«процесс внутри процесса» - у Win32 есть волокна. – W55tKQbuRu28Q4xv

+2

Но волокна самонастраиваются - РЕЗЬБЫ (и не имеют смысла в случаях МОСТ). Процесс определяется как имеющий барьер памяти, который отсутствует в волокне. Таким образом, волокно отнюдь не является процессом внутри процесса. – TomTom

+2

Вы явно не смотрели дизайн исполнения Erlang. Да, вы можете реализовать Erlang-подобные процессы на уровне приложения, но это, вероятно, будет означать совместную многозадачность, технику, которую я не видел с момента моего DOS/Win16. Если у вас есть поддержка во время выполнения, вы можете получить этот эффект с упреждающей многозадачностью, но это было бы то, что MS пришлось бы добавить в .NET. –

7

CLR может быть размещен и предоставляет механизмы для хоста, чтобы реализовать свою собственную задачу абстракции. Теоретически, они могут быть нитями, волокнами, LWP - что угодно, пока хозяин реализует necessaryinterfaces.

Правильно ли это немного сложно. MS воспользовалась возможностью, чтобы разместить CLR в режиме Fibre Channel SQL Server.

В последний момент были некоторые проблемы с нагрузкой, поэтому они надавили на него вилку в соответствии с Joe Duffy и Dino Vhieland (кто управлял series about writing a custom CLR host that implements its own task abstraction - with fibers - on his blog).
Прямо сейчас есть какая-то сантехника отсутствует - ICLRTask::SwitchOut() - и даже если обойти это, те же ошибки, которые попадают в MS на итерации стресс-теста, вероятно, будут преследовать и авантюристскую душу.

Предположим на мгновение, что все проблемы каким-то образом устранены, и вся среда выполнения готова работать на волокнах, LWPs, что угодно. По-прежнему существует проблема P/Invoke, которая может потенциально вызвать блокирующие операции. Такой вид планирования трудно обойтись без поддержки ядра.

Это адресовано в 64-битных версиях Windows 7 и Windows Server 2008 R2. В настоящее время существует User-Mode Scheduling, который может возвращать управление в пользовательский режим - в отличие от диспетчера режима ядра, если блокирует вызов в ядре. Кроме того, эти запланированные потоки пользовательского режима являются реальными потоками с их собственным TLS. Это отличные улучшения, и многие головные боли в волоконном режиме исчезают.

Прямо сейчас, UMS is utilized в Concurrency Runtime, то есть available for C++ and is part of the C Runtime Library (CRT).
Последнее означает, что вы можете использовать его из коробки с Visual Studio 2010.

+0

Выполняется ли какое-либо из этих действий, если вы ограничиваете его использование к F # или другому функциональному языку, чтобы избежать некоторых трудностей с одним процессом, сбрасывающим чужое хранилище? –

+0

@Warren: Управление задачами здесь действительно не касается того, чтобы предотвратить запись нити/волокна/LWP в память другого. В конце концов, это предполагаемое поведение - вы делаете это каждый раз, когда запускаете многопоточную программу - все потоки доступа и обмена памятью процесса. –

+0

@ Уоррен: ... с учетом сказанного, избегая или сводя к минимуму общее состояние, это один из великих способов увеличить параллелизм. Это можно сделать и на C#, хотя язык не обеспечивает или не поощряет его. –

4

Вы имеете дело с retlang? Я только читал об этом, но я ничего не сделал с этим, но ...

1

Процесс Erlang аналогичен работающему методу параллельно, но переменная erlang может быть привязана только один раз, поэтому она является потокобезопасной, которая не находится в C#.

так что вам нужно две вещи в C#, потокобезопасность и параллельность.

C# имеет System.Threading.Task, вы можете запускать множество задач в vm. C# vm будет планировать эту задачу в разных рабочих потоках.

Но задача не потокобезопасна, вам нужно создать класс под названием «Актер» и поставить государство в Актер.

Актер имеет System.Threading.SynchronizationContext и многие методы async, например.

class Actor { 
    public SynchronizationContext _context; 

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


    public async Task Method1() { 
     await _context; 

     doSomething(); 
    } 

} 

Когда другие актеры называют методы асинхронных в этом актере, он будет создавать задачу, и задача будет планироваться VM.

Вам также необходимо реализовать ожидаемый и потокобезопасный SynchronizationContext.

Это контекст, безопасный для потоков.

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

сделать 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 для 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(){} 
} 

тогда вы получите класс Actor с задачей и поточно, которые, как процесс в Erlang.