是否可以在.NET中使用C#实现基于事件的异步模式而无需多线程?

Jef*_*eff 14 c# events multithreading asynchronous node.js

我很惊讶Node.js的架构设计,并想知道C#是否能够进行这样的设计:

异步,基于事件/事件循环,无多线程的非阻塞I/O.

Tom*_*cek 13

我认为BeginXyz实现标准异步编程模型的所有操作都在线程池线程上运行回调,这使得应用程序自动进行多线程.

但是,您可以通过使用Control.Invoke或更常见地为Windows应用程序维护的单个GUI线程同步所有操作来实现单线程异步编程模型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)
  }));
Run Code Online (Sandbox Code Playgroud)

标记为(2)的代码将继续在与(1)中的代码相同的线程上运行,因此您将仅使用线程池线程将回发转发回原始(单个)线程.

作为一个侧面说明,这是更直接地在F#异步工作流的支持,它可用于GUI编程的相当优雅的风格,如下描述.我不知道node.js,但我想你也可能对F#异步工作流程感到惊讶,因为它们非常适合异步/基于事件/ ...编程风格:-)


Ben*_*esh 7

我正在.NET中作为一个宠物项目做这样的事情.我称之为ALE(另一个循环赛事) ......因为啤酒.

它现在非常阿拉伯,但它都是自制软件,因为像你一样,我想知道它是否可以完成.

  • 这是一个事件循环架构.
  • 它利用.NET的非阻塞异步I/O调用
  • 它使用回调式调用来帮助开发人员编写更具可读性的异步代码.
  • 异步Web套接字实现
  • 异步http服务器实现
  • 异步sql客户端实现

与其他一些尝试不同,我看到它不仅仅是一个带有事件循环的Web服务器.您可以编写任何类型的基于事件循环的应用程序.


以下代码将:

  • 启动事件循环
  • 在端口1337上启动Web服务器
  • 在端口1338上启动Web套接字服务器
  • 然后用它读取一个文件和"DoSomething":
EventLoop.Start(() => {

    //create a web server
    Server.Create((req, res) => {
        res.Write("<h1>Hello World</h1>");
    }).Listen("http://*:1337");


    //start a web socket server
    Net.CreateServer((socket) => {
        socket.Receive((text) => {
             socket.Send("Echo: " + text);
        });
    }).Listen("127.0.0.1", 1338, "http://origin.com");


    //Read a file
    File.ReadAllText(@"C:\Foo.txt", (text) => {
        DoSomething(text);
    });
});
Run Code Online (Sandbox Code Playgroud)

所以我猜我的回答是"是",它可以用C#...或几乎任何语言来完成.真正的诀窍是能够利用本机非阻塞I/O.

有关该项目的更多信息将在此处发布.


Mar*_*ett 6

当然,它只需要一个事件循环.就像是:

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 = "!";
}
Run Code Online (Sandbox Code Playgroud)

很快,你就会想要摆脱DoSomething并要求所有的工作都要注册MyThingsToDo.然后,你会想要传递一个enum或者某个东西ThingToDo,告诉它为什么它在做某事.那时,你会发现你有一个消息泵.

顺便说一句,我要说的node.js是,它正在运行在一个多线程的操作系统和应用程序上.没有它,每次对网络或磁盘的调用都会阻塞.