我有一个非常强大的玩具网络应用程序
func PerfServiceHandler(w http.ResponseWriter, req *http.Request)
{
start := time.Now()
w.Header().Set("Content-Type", "application/json")
x := 0
for i := 0; i < 200000000; i++ {
x = x + 1
x = x - 1
}
elapsed := time.Since(start)
w.Write([]byte(fmt.Sprintf("Time Elapsed %s", elapsed)))
}
func main()
{
http.HandleFunc("/perf", PerfServiceHandler)
http.ListenAndServe(":3000", nil)
}
上述功能需要大约120 ms才能执行。但当我用500个并发用户(siege -t30s -i -v -c500 http://localhost:3000/perf)对这个应用程序进行负载测试时得到的结果
有人可以回答我的问题: -
环境: -
Go - go1.4.1 linux/amd64
OS - Linux 3.2.0-4-amd64 #1 SMP Debian 3.2.65-1+deb7u2 x86_64 GNU/Linux
Processor - 2.6Ghz (Intel(R) Xeon(R) CPU E5-2640 v3 @ 2.60GHz)
RAM - 64 GB
操作系统参数 -
nproc - 32
cat /proc/sys/kernel/threads-max - 1031126
ulimit -u - 515563
ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 515563
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 65536
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 515563
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
答案 0 :(得分:4)
多个goroutine可以对应一个os线程。此处描述了设计:https://docs.google.com/document/d/1TTj4T2JO42uD5ID9e89oa0sLKhJYD0Y_kqxDv3I3XMw/edit,它引用了本文:http://supertech.csail.mit.edu/papers/steal.pdf。
问题:
即使有500个并发请求到达服务器,操作系统线程的数量仍然停留在35个OS线程上[...]有人可以解释一下这种行为吗?
由于您将GOMAXPROCS设置为CPU数量,因此一次只运行那么多goroutine。
可能有点令人困惑的一件事是goroutine并不总是在运行(有时候它们“很忙”)。例如,如果您读取文件,而操作系统正在执行该工作,则goroutine正忙,调度程序将选择另一个goroutine运行(假设有一个)。一旦文件读取完成,goroutine就会回到“runnable”goroutines列表中。
OS级别线程的创建由调度程序处理,并且系统级调用之间存在其他复杂性。 (有时候你需要一个真实的专用线程。参见:LockOSThread)但你不应该期待大量的线程。
可以吗? OS线程会以某种方式增加(从OS或GOlang)?
我认为使用LockOSThread
可能会导致新线程的创建,但这并不重要:
如果没有,这会改善性能吗? OS线程的数量增加了吗?
没有。您的CPU从根本上限制了它可以同时执行的操作数量。 Goroutines工作是因为事实证明大多数操作都是以某种方式绑定IO,但如果你真的在做一些CPU限制,那么在这个问题上投入更多线程将无济于事。事实上,它可能会使情况变得更糟,因为线程之间切换涉及开销。
换句话说,Go在这里做出了正确的决定。
有人可以建议其他一些优化此应用的方法吗?
for i := 0; i < 200000000; i++ {
x = x + 1
x = x - 1
}
我认为你编写这段代码只是为了让CPU做很多工作?实际代码是什么样的?
您最好的选择是找到一种优化代码的方法,以便减少CPU时间。如果那是不可能的(它已经高度优化),那么你需要添加更多的计算机/ CPU。获得更好的计算机,或更多的计算机。
对于多台计算机,您可以将负载均衡器放在所有计算机的前面,并且可以轻松扩展。
您也可以通过将此工作从Web服务器上移除并将其移至某个后端系统来获益。考虑使用工作队列。