.NET中是否可以使用非阻塞,单线程,异步Web服务器(如Node.js)? [英] Is a non-blocking, single-threaded, asynchronous web server (like Node.js) possible in .NET?

查看:249
本文介绍了.NET中是否可以使用非阻塞,单线程,异步Web服务器(如Node.js)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在查看这个问题,寻找一种创建单线程,基于事件的非阻塞异步Web服务器。

I was looking at this question, looking for a way to create a single-threaded, event-based nonblocking asynchronous web server in .NET.

这个答案首先,通过声明代码的正文运行在单个线程中,首先看起来很有希望。

This answer looked promising at first, by claiming that the body of the code runs in a single thread.

但是,我在C#中测试了这个:

However, I tested this in C#:

using System;
using System.IO;
using System.Threading;

class Program
{
    static void Main()
    {
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId);

        var sc = new SynchronizationContext();
        SynchronizationContext.SetSynchronizationContext(sc);
        {
            var path = Environment.ExpandEnvironmentVariables(
                @"%SystemRoot%\Notepad.exe");
            var fs = new FileStream(path, FileMode.Open,
                FileAccess.Read, FileShare.ReadWrite, 1024 * 4, true);
            var bytes = new byte[1024];
            fs.BeginRead(bytes, 0, bytes.Length, ar =>
            {
                sc.Post(dummy =>
                {
                    var res = fs.EndRead(ar);

                    // Are we in the same thread?
                    Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
                }, null);
            }, null);
        }
        Thread.Sleep(100);
    }
}

结果是:


1

5

1
5

所以似乎,与答案相反,启动阅读的线程和结束阅读的线程都是相同的。

So it seems like, contrary to the answer, the thread initiating the read and the thread ending the read are not the same.

所以现在我的问题是如何在.NET中实现一个单线程,基于事件的非阻塞异步Web服务器?

So now my question is, how do you to achieve a single-threaded, event-based nonblocking asynchronous web server in .NET?

推荐答案

整个 SetSynchronizationContext 是一个红色的鲱鱼,这只是一个编组机制,工作仍然发生在IO线程池中。

The whole SetSynchronizationContext is a red herring, this is just a mechanism for marshalling, the work still happens in the IO Thread Pool.

您要求的是排队和收获异步过程调用,从主线程获取所有IO工作。许多更高级别的框架包装了这种功能,最着名的一个是 libevent

What you are asking for is a way to queue and harvest Asynchronous Procedure Calls for all your IO work from the main thread. Many higher level frameworks wrap this kind functionality, the most famous one being libevent.

这里有一个很好的概述: epoll,poll,threadpool有什么区别?

There is a great recap on the various options here: Whats the difference between epoll, poll, threadpool?.

.NET已经为您提供了缩放,当您调用 BeginXYZ 时,有一个特殊的IO线程池来处理IO访问code>方法。该IO线程池每个处理器上必须至少有1个线程。请参阅: ThreadPool.SetMaxThreads

.NET already takes care of scaling for you by have a special "IO Thread Pool" that handles IO access when you call the BeginXYZ methods. This IO Thread Pool must have at least 1 thread per processor on the box. see: ThreadPool.SetMaxThreads.

如果单线程应用程序是一个关键要求(有些疯狂的原因),当然可以使用 DllImport (见这里的例子

If single threaded app is a critical requirement (for some crazy reason) you could, of course, interop all of this stuff in using DllImport (see an example here)

然而,这将是一个非常复杂和有风险的任务

However it would be a very complex and risky task:


为什么我们不支持APC作为完成机制? APC真的不是用户代码的一个很好的通用完成机制。管理由APC引入的重入几乎是不可能的;任何时候阻止锁定,例如,一些任意的I / O完成可能会覆盖你的线程。它可能会尝试获取自己的锁,这可能会引起锁定顺序问题,从而导致死锁。防止这种情况需要细致的设计,以及确保别人的代码永远不会在您的警报等待期间运行的能力,反之亦然。这大大限制了APC的有用性。

Why don't we support APCs as a completion mechanism? APCs are really not a good general-purpose completion mechanism for user code. Managing the reentrancy introduced by APCs is nearly impossible; any time you block on a lock, for example, some arbitrary I/O completion might take over your thread. It might try to acquire locks of its own, which may introduce lock ordering problems and thus deadlock. Preventing this requires meticulous design, and the ability to make sure that someone else's code will never run during your alertable wait, and vice-versa. This greatly limits the usefulness of APCs.

所以,总结一下。如果您想要使用APC和完成端口完成所有工作的单线程管理进程,则需要手动对其进行编码。建设它将是风险和棘手的。

So, to recap. If you want a single threaded managed process that does all its work using APC and completion ports, you are going to have to hand code it. Building it would be risky and tricky.

如果您只想要高级网络,则可以继续使用 BeginXYZ 和家庭并放心,它将表现良好,因为它使用APC。您在线程和.NET特定实现之间支付小费用编组的东西。

If you simply want high scale networking, you can keep using BeginXYZ and family and rest assured that it will perform well, since it uses APC. You pay a minor price marshalling stuff between threads and the .NET particular implementation.

来自: http ://msdn.microsoft.com/en-us/magazine/cc300760.aspx


下一步放大服务器是使用异步I / O。异步I / O减轻了创建和管理线程的需要。这导致更简单的代码,也是更高效的I / O模型。异步I / O利用回调来处理传入的数据和连接,这意味着没有列表可以进行设置和扫描,并且不需要创建新的工作线程来处理挂起的I / O。

The next step in scaling up the server is to use asynchronous I/O. Asynchronous I/O alleviates the need to create and manage threads. This leads to much simpler code and also is a more efficient I/O model. Asynchronous I/O utilizes callbacks to handle incoming data and connections, which means there are no lists to set up and scan and there is no need to create new worker threads to deal with the pending I/O.

一个有趣的事实是,单线程不是使用完整端口在Windows上执行异步套接字的最快方法,请参见: http://doc.sch130.nsc.ru/www.sysinternals.com/ntw2k/ info / comport.shtml

An interesting, side fact, is that single threaded is not the fastest way to do async sockets on Windows using completion ports see: http://doc.sch130.nsc.ru/www.sysinternals.com/ntw2k/info/comport.shtml


服务器的目标是通过使其线程避免使尽可能少的上下文切换不必要的阻塞,同时通过使用多个线程最大化并行度。理想情况是,在每个处理器上主动为客户端请求提供线程,如果在完成请求时还有其他请求等待,那么这些线程不会阻塞。为了使其正常工作,一个处理客户端请求在I / O上阻塞的应用程序必须有一种方法来激活另一个线程(如在处理中作为文件读取时)。

The goal of a server is to incur as few context switches as possible by having its threads avoid unnecessary blocking, while at the same time maximizing parallelism by using multiple threads. The ideal is for there to be a thread actively servicing a client request on every processor and for those threads not to block if there are additional requests waiting when they complete a request. For this to work correctly however, there must be a way for the application to activate another thread when one processing a client request blocks on I/O (like when it reads from a file as part of the processing).

这篇关于.NET中是否可以使用非阻塞,单线程,异步Web服务器(如Node.js)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆