Действительно ли это возможно в.NET, с помощью C#, достигнуть события основывало асинхронный шаблон без многопоточности?

Я поражен архитектурным проектом Node.js и задавался вопросом, способен ли C# к такому дизайну:

Асинхронный, событие, базирующееся / цикл событий, не блокируя ввод-вывод без многопоточности.

14
задан Peter Mortensen 20 November 2013 в 15:48
поделиться

5 ответов

Я думаю, что все операции BeginXyz, реализующие стандартную асинхронную модель программирования, запускают обратный вызов на потоке пула потоков, что автоматически делает приложение многопоточным.

Однако вы можете добиться однопоточной модели асинхронного программирования, синхронизируя все операции через единственный поток GUI, который поддерживается для windows-приложений с помощью Control.Invoke или, в более общем случае, SynchronizationContext.

Каждый вызов BeginXyz должен быть переписан следующим образом:

// Start asynchronous operation here (1)
var originalContext = SynchronizationContext.Current;
obj.BeginFoo(ar =>
  // Switch to the original thread
  originalContext.Post(ignored => {
    var res = obj.EndFoo(); 
    // Continue here (2)
  }));

Код, обозначенный как (2), будет продолжать выполняться в том же потоке, что и код в (1), поэтому вы будете использовать поток thread-pool только для переадресации постбэка обратно в исходный (единственный) поток.

В качестве примечания, это более непосредственно поддерживается асинхронными рабочими процессами в F# и может быть использовано для довольно элегантного стиля программирования GUI как описано здесь . Я не знаю node.js, но полагаю, что вы также можете быть поражены асинхронными рабочими процессами в F#, поскольку они действительно круты для асинхронного/событийного/... стиля программирования :-)

.
13
ответ дан 1 December 2019 в 07:51
поделиться

Конечно, для этого нужен только цикл событий. Примерно так:

class EventLoop {
   List<Action> MyThingsToDo { get; set; }

   public void WillYouDo(Action thing) {
      this.MyThingsToDo.Add(thing);
   }

   public void Start(Action yourThing) {
      while (true) {
         Do(yourThing);

         foreach (var myThing in this.MyThingsToDo) {
            Do(myThing);
         }
         this.MyThingsToDo.Clear();
      }
   }

   void Do(Action thing) { 
      thing();
   }
}

class Program {
    static readonly EventLoop e = new EventLoop();

    static void Main() {
        e.Start(DoSomething);
    }

    static int i = 0;
    static void DoSomething() {
        Console.WriteLine("Doing something...");
        e.WillYouDo(() => {
            results += (i++).ToString();
        });
        Console.WriteLine(results);
    }

    static string results = "!";
}

Вскоре вы захотите избавиться от DoSomething и потребовать, чтобы вся работа регистрировалась в MyThingsToDo . Затем вы захотите передать перечисление или что-то в этом роде каждому ThingToDo , которое сообщает ему, почему он что-то делает. В этот момент вы поймете, что у вас есть насос сообщений .

Кстати, я бы сказал, что node.js приукрашивает тот факт, что он работает в ОС и в многопоточном приложении. Без этого каждый вызов сети или диска будет заблокирован.

6
ответ дан 1 December 2019 в 07:51
поделиться

Реактивные расширения для .NET (Rx) предназначены для асинхронного и параллельного программирования. Это позволяет вам программировать реактивным или интерактивным способом, без блокировки. Вы используете операторы запросов LINQ и новые для интерфейсов IObservable / IObserver, которые являются частью Rx. Rx предоставляет математический двойник IEnumerable / IEnumerator в форме IObservable / IObserver, что означает, что вы можете декларативно использовать все стандартные операторы запросов LINQ, а не напрямую использовать многопоточные API.

3
ответ дан 1 December 2019 в 07:51
поделиться

ваш пример node.js на самом деле неприменим, поскольку сервер, на котором он работает, выполняет всю необходимую многопоточность. Если события выполняются на основе одного и того же внешнего тактового сигнала, они не асинхронны. Вы можете обойти это, запустив другое приложение, которое создаст в системе два процесса.

Невозможно заставить одно и то же приложение, работающее как отдельный процесс в одной системе, выполнять асинхронные события, не имея другого потока.

Подробнее см. Вопрос об асинхронности и многопоточности .

2
ответ дан 1 December 2019 в 07:51
поделиться

Не уверен, что это то, что вы ищете. .NET может выполнять асинхронные обратные вызовы без явной многопоточности.

2
ответ дан 1 December 2019 в 07:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: