jjzjj

c# - 通过线程经济的可扩展性 : async operations vs. 线程池上的多线程生产者/消费者队列?

coder 2023-10-30 原文

异步编程是一种通过线程经济实现 Web 服务器可扩展性的方法,因此很少的非阻塞线程可以处理许多同时发生的请求。例如,Node.js 使用异步操作仅使用单个线程即可实现可伸缩性。

我目前正在使用数据库 MongoDb,它是官方的 C# 驱动程序,尚不支持异步操作。因此,我正在考虑使用一个简单的生产者/消费者队列来处理 mongodb 请求,以减少阻塞线程的数量。这是通过让线程池线程在队列中插入数据库请求然后让它们继续执行其他任务来完成的。该队列还有一个专用线程执行实际的数据库请求,当请求返回结果时,结果将移交给线程池线程。

但是,我现在想知道在使用线程池时是否有必要使用队列(通过 C# 4.0 中的 TPL 和任务),因为线程池对线程数有最大限制。当达到此限制时,请求将排队直到线程池线程可用。听起来好像线程池提供了开箱即用的队列功能,因此使用我自己的队列什么的也没有任何好处?

我想知道的另一件事是来自优秀的“C# 4.0 in a nutshell”书页的以下评论。 928:“不阻塞规则有一个异常(exception)。在调用数据库服务器时阻塞通常是可以的 - 如果其他线程正在竞争同一服务器。这是因为在高并发系统中,必须设计数据库这样大多数查询的执行速度都非常快。如果您最终遇到数千个并发查询,这意味着请求到达数据库的速度快于它处理它们的速度。那么线程经济是您最不担心的事情。”

与阻止其他内容(例如对其他服务器的请求)相比,我不明白为什么可以阻止数据库请求。最好不要阻塞数据库请求,这样线程就可以被释放来服务于其他可能不需要数据库访问的请求。

总结一下:线程经济是不是可以靠最大线程池线程数来实现,还是做一个简单的生产者消费者队列更好,为什么阻塞调用数据库服务器就可以了?

最佳答案

在数据库查询上阻塞 TP 线程是不行的。引用的短语规定,只有当 所有 TP 线程都阻塞此类查询时才可以。不能反驳,但它似乎相当人为。

线程池管理器的主要工作是确保它运行的线程永远不会超过机器中的可用内核数。因为这会使线程效率低下,所以线程之间的上下文切换非常昂贵。然而,如果正在执行的 TP 线程阻塞并且没有做任何实际工作,那将不会很好地工作。 TP 管理器不够聪明,无法知道 TP 线程正在阻塞并且无法预测它将阻塞多长时间。只有 dbase 引擎会猜测它,但它不会告诉。

所以 TP 管理器有一个简单的算法来处理这个问题,如果没有一个正在执行的 TP 线程在合理的时间内完成,那么它允许另一个运行。您现在的事件线程数 多于 cpu 内核数。 “合理时间”是 .NET TP 管理器的半秒。

如有必要,这会继续,只要现有的线程停滞不前,就允许额外的线程运行。

实际上达到 ThreadPool.GetMaxThreads() 数量的线程是非常不健康的。这是一个巨大的数字,是机器核心数量的 250 倍。在 4 核机器上,需要 999 个执行线程在 499 秒内没有取得任何进展才能达到最大值。这些线程会为其堆栈占用很酷的 千兆字节 地址空间。如果它到达那里,您方式超出了“这里有问题”的观察。

此答案中有一些易于量化的数字。一旦某个操作开始花费超过半秒的时间,那么您就需要开始考虑让它在专用线程上执行。燃烧半秒只有通过阻塞才能真正实现,因此线程比 TP 线程更合适。是的,使用线程安全队列来为其提供操作请求。对待处理请求的数量设置上限也很重要,这样您就不会淹没队列。通过阻塞来限制生产者。当然,不要忘记一年后会发生什么。数据库在老化时永远不会变快。

关于c# - 通过线程经济的可扩展性 : async operations vs. 线程池上的多线程生产者/消费者队列?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9029595/

有关c# - 通过线程经济的可扩展性 : async operations vs. 线程池上的多线程生产者/消费者队列?的更多相关文章

  1. ruby - 通过 rvm 升级 ruby​​gems 的问题 - 2

    尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub

  2. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  3. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

  4. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  5. ruby - 通过 RVM (OSX Mountain Lion) 安装 Ruby 2.0.0-p247 时遇到问题 - 2

    我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search

  6. ruby-on-rails - Enumerator.new 如何处理已通过的 block ? - 2

    我在理解Enumerator.new方法的工作原理时遇到了一些困难。假设文档中的示例:fib=Enumerator.newdo|y|a=b=1loopdoy[1,1,2,3,5,8,13,21,34,55]循环中断条件在哪里,它如何知道循环应该迭代多少次(因为它没有任何明确的中断条件并且看起来像无限循环)? 最佳答案 Enumerator使用Fibers在内部。您的示例等效于:require'fiber'fiber=Fiber.newdoa=b=1loopdoFiber.yieldaa,b=b,a+bendend10.times.m

  7. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  8. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

  9. 通过 MacPorts 的 RubyGems 是个好主意吗? - 2

    从MB升级到新的MBP后,Apple的迁移助手没有移动我的gem。我这次是通过macports安装ruby​​gems,希望在下次升级时避免这种情况。有什么我应该注意的陷阱吗? 最佳答案 如果你想把你的gems安装在你的主目录中(在传输过程中应该复制过来,作为一个附带的好处,会让你以你自己的身份运行geminstall,而不是root),将gemhome:键设置为您在~/.gemrc中的主目录中的路径. 关于通过MacPorts的RubyGems是个好主意吗?,我们在StackOverf

  10. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

随机推荐