Golang Go语言中在项目的一些思考:线程池里究竟该放多少线程?

发布于 1周前 作者 gougou168 来自 Go语言

在最近的使用 golang 开发中,发现 goroutine 实际上解决的只是线程资源的调度,避免大量线程带来的资源瓶颈。

而在实际开发中,更多遇到的问题是其他的资源瓶颈带来的。比如 tcp 连接、数据库连接、带锁的资源等。并不只是一个简单的线程资源的问题,当使用这些资源时,还是需要要用到使用传统线程时的一些思想/技术。

所以说感觉并发这个问题是个大坑,软件工程没有银弹。

当然了, golang 能合理调度线程资源已经是语言的一个很大进步了,不用让程序员自己费心调度线程。

具体的思考我写到博客里了,这里贴代码和图不太方便,我放个链接吧:

并发难 | 池里究竟该放多少线程?https://lengzzz.com/note/concurrency-roadblock-how-many-threads-should-be-in-pool

只是个人观点,抛砖引玉,大家多多讨论一下。

软件工程没有银弹,路漫漫其修远兮,吾将上下而求索。


Golang Go语言中在项目的一些思考:线程池里究竟该放多少线程?

更多关于Golang Go语言中在项目的一些思考:线程池里究竟该放多少线程?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

25 回复

一般性而言, CPU 密集运算,和 CPU 核数相等就行了

更多关于Golang Go语言中在项目的一些思考:线程池里究竟该放多少线程?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


最佳线程数量 = (线程等待时间 + 线程 CPU 时间) / 线程 CPU 时间 * CPU 数量
平均响应时间 = 并发线程数 / 最佳线程数 * 最佳线程响应时间

最后, LZ 研究的东西跟线程池半毛钱关系都没有

是的,运算密集型的应用应该是最可控的。但实际中都是复杂到不行的 IO 密集型应用😳



这个公式也并没有考虑到 IO 资源的瓶颈问题。我在实际中首先使用单线程做了 pprof 。总执行时间 130s ,卡在 Syscall 上的时间是 90s 。

那么按道理来说应该是 130 / (130 - 90) * 核数 = 52 。

但实际上,开 32 个线程,数据库就崩了。这是 IO 资源有瓶颈导致的。

好吧,确实和有没有线程池关系不大,重点在线程数量上。

IO 密集优化的线程池大小把平均 IO 等待时间和 CPU 时间的比值乘到 CPU 核心数就可以了(好像和 回复里的公式差不多… )。
开 32 个线程数据库就崩了这种事情… 是数据库的瓶颈。

goroutine 和一般线程不是一个东西 基本不需要计算这些量

嗯嗯,确实是数据库的,但有时更复杂,并发高了之后 connect 函数也会莫名其妙超时。

我以前也是你这种想法,直到发现 goroutine 只解决了线程资源瓶颈的问题。其他 IO 资源的瓶颈问题还是需要自行解决的。

LZ 想问的大概是数据库的连接池开多大,我自己倾向认为数据库是 CPU 密集型的(数据库对 IO 什么的有各种的优化来着),所以一般是连接数=核心数。榨干机器性能的任务就交给数据库来处理了,比较不赞同增加连接数逼迫数据库榨干机器性能的方法。

数据库的连接肯定得限制的,还有文件加锁都属于常识啦。楼主你这个吐槽的对象都不是同一个好么

数据库崩,就去调数据库参数
connect 超时,就加网络带宽
和 golang 其实没什么关系
而且,把 goroutine 看成线程就对了,性质基本一致

是问线程池的大小吧= =



我的意思是,各种对并发支持的好的语言,也只是在 “平衡线程资源” 这一点上做到了优化。对于实际中更常见的 IO 资源瓶颈引来的问题,还是得自己动手调。



调并发量本身就是调并发程序必不可少的一步,数据库参数再怎么调也架不住程序瞎搞啊。


对的

这个就需要你手动调啊,我的电脑虽然是四核,但以前写爬虫的时候发现 10 个左右更快一点。

和线程池有个一毛钱关系吗?线程不就是时间片,不装逼就不能活了

这个时候又要推一下 goroutine pool lib 了 https://github.com/Comdex/octopus

这时候就应该去了解一下 java

手动黑人问号

嗯嗯,我也用了一个 goroutine pool https://github.com/go-playground/pool 才 100 多行,很轻量

java 转的 golang ,以前写 java 和 c#

你用 java 多久了?

上家公司用 java , spring mvc 什么的。在那里工作了 7 个月。之前在学校也有做过。

😓还是多去看看吧

有话就说,吞吞吐吐的真是烦

你以为你谁啊。没兴趣义务多说。 sb

大家都是做技术的,说话直来直去就行了,如果您觉得我哪里说得不对的就直说,没想明白怎么说就闭嘴。不用您费心回复这三条。

还有楼上这位,不知道我的主题哪句话戳到您可怜的玻璃自尊心了,让您感觉我在装逼。手动呵呵。

以前感觉在 v2 的都是同行,姿势水平都是比较高一些的人,没想到也能碰上这种垃圾。

两位我已 block 。早上刚上班说话比较冲,如果您二位感觉有啥不爽的,您就憋着吧。

最后 at 一下站长,这种直接说脏话的,应该封号的吧。

在Golang(Go语言)项目中,关于线程池里应放置多少线程的问题,实际上更多关联于Goroutine的调度与系统的资源利用,因为Go语言运行时本身已经很好地抽象了线程管理,通过Goroutine和M(机器线程)、P(处理器)的调度模型实现了高效的并发。

  1. 系统资源限制:首先应考虑的是系统资源,包括CPU核心数、内存以及I/O性能。一般来说,理想的Goroutine数量可以略多于CPU核心数,以便充分利用多核优势并保持一定的上下文切换开销。

  2. 任务性质:任务的计算密集度与I/O密集度决定了Goroutine的最优数量。对于计算密集型任务,Goroutine数量接近CPU核心数通常较优;而对于I/O密集型任务,由于I/O等待会释放处理器,可以配置更多的Goroutine来保持CPU的忙碌。

  3. 动态调整:在实际应用中,很难静态确定最优Goroutine数量。可以考虑使用监控工具观察系统的资源使用情况,如CPU利用率、内存占用等,并根据应用性能进行动态调整。

  4. Go运行时优化:Go的运行时已经为Goroutine的调度做了大量优化,通常不需要开发者过多干预。除非有明确的性能瓶颈,否则可以信任Go的运行时调度器来做出合理决策。

综上所述,线程池(在Go中更多表现为Goroutine池)的大小应根据实际系统资源、任务特性及运行时表现综合考量,灵活调整以达到最佳性能。

回到顶部