当前位置: 首页 > 面试题库 >

.NET中是否可以使用非阻塞,单线程,异步Web服务器(例如Node.js)?

梅飞宇
2023-03-14
问题内容

但是,我在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

因此,它似乎是,相反的答案,线程开始读取和结束读线程是 一样的。

因此,现在我的问题是,如何在.NET中实现 单线程 ,基于事件的无阻塞异步Web服务器?


问题答案:

整个过程SetSynchronizationContext是一条红鲱鱼,这只是一种编组机制,工作仍在IO线程池中进行。

您需要的是一种从主线程对所有IO工作进行排队和收集异步过程调用的方法。许多更高级别的框架都包装了这种功能,其中最著名的就是libevent。

这里的各种选项都有很好的概括:epoll,poll和threadpool之间有什么区别?。

.NET已经拥有一个特殊的“
IO线程池”来为您进行扩展,当您调用BeginXYZ方法时,该线程池可以处理IO访问。该IO线程池在包装盒上每个处理器必须至少具有1个线程。请参阅:ThreadPool.SetMaxThreads。

如果单线程应用是一个关键需求(出于某种疯狂的原因),那么您当然可以在使用DllImport的过程中互操作所有这些东西(请参见此处的示例)

但是,这将是一个非常复杂和冒险的任务:

我们为什么不支持APC作为完成机制?对于用户代码,APC确实不是一个好的通用完成机制。管理APC引入的可重入性几乎是不可能的。例如,每当您阻塞锁时,任意的I
/
O完成都可能会占用您的线程。它可能尝试获取自己的锁,这可能会引入锁排序问题,从而导致死锁。防止这种情况需要精心设计,并具有确保您的警报等待期间永远不会运行别人的代码的能力,反之亦然。这极大地限制了APC的用途。

因此,回顾一下。如果您想要一个使用APC和完成端口来完成其所有工作的 单线程 托管进程,则必须手动对其进行编码。构建它是冒险和棘手的。

如果您只想进行 大规模
联网,则可以继续使用BeginXYZ并保持家庭状态,并放心,因为它使用APC,所以性能良好。您只需支付少量费用即可在线程和.NET特定实现之间进行编组。

来自:http :
//msdn.microsoft.com/zh-cn/magazine/cc300760.aspx

扩展服务器的下一步是使用异步I / O。异步I / O减轻了创建和管理线程的需要。这样可以简化代码,并且是更有效的I / O模型。异步I /
O利用回调来处理传入的数据和连接,这意味着不需要设置和扫描列表,也无需创建新的工作线程来处理未决的I / O。

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

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



 类似资料:
  • 我有一个使用Spring Boot设计的RestFul Webservice。 web服务相当繁重,因为它必须在启动时进行大量的数据库调用,并且有些端到其他端进行大量的IO操作来提供结果。 我想让Restful Api成为异步的,这样它就可以更有伸缩性,而且它花时间来提供它的结果。 我甚至实现了这一点,但我无法测试这是否是异步的。 如果我想要 如果向url/all发出请求

  • 问题内容: 我想使用redis的pubsub传输一些消息,但不想使用阻止,例如以下代码: 最后一部分将被阻止。我只想检查给定频道中是否有数据,该如何完成?有没有类似的方法? 问题答案: 我认为那不可能。通道没有任何“当前数据”,您订阅了一个通道并开始接收该通道上其他客户端推送的消息,因此它是一个阻塞的API。另外,如果您查看pub / sub 的Redis Commands文档,将会更加清楚。

  • C#中的许多内置IO函数是非阻塞的,也就是说,它们在等待操作完成时不会抓住线程不放。 例如,返回的是非阻塞的。 它不只是暂停它正在使用的线程,它实际上释放了线程,以便其他进程可以使用它。 我假设这是通过调用OS来实现的,这样OS在检索到文件时就回调到程序,而程序不必浪费一个线程来等待它。 是否可以自己创建一个非阻塞的异步任务? 执行类似的操作显然不会像那样释放当前线程。 我意识到Hibernate

  • 我认为下面的流量链将通过事件循环放置/执行(像JS)。因此,运行下面的代码将首先打印阻塞循环&然后将执行通量链。 但是,整个通量总是先执行,然后才移动到循环。[我确实有一些语句正在阻塞。但是有两个阶段] 当我们使用reactor时,通过使用一些调度程序来实现异步/非阻塞行为的唯一方法? 如果我不使用任何调度器,并让代码使用当前线程执行,那么即使对于IO密集型应用程序,使用WebFlux而不是Spr

  • 现在我们已经知道了Java NIO里面那些非阻塞特性是怎么工作的,但是要设计一个非阻塞的服务仍旧比较困难。非阻塞IO相对传统的阻塞IO给开发者带来了更多的挑战。在本节非阻塞服务的讲解中,我们一起来讨论这些会面临的主要挑战,同时也会给出一些潜在的解决方案。 查找关于设计非阻塞服务的相关资料是比较难的,本文提出的解决方案也只能是基于笔者个人的工作经验,构思。如果你有其他的解决方案或者是更好的点子,那么

  • 我刚刚开始尝试了解RxJava,以便我可以使用项目反应器重构旧版SOA系统来使用非阻塞异步微服务。 目前,我正在做一项可行性研究,并考虑使用类似spoon的东西来转换遗留服务代码(但这与这个问题无关) 我想知道如何使用reactor bus Request/Reply语法来替换这个同步服务代码。或者即使我应该使用完全不同的Reactor结构。 这里是一个遗留soa服务的示例,它是人为设计的,因此可