简洁和高效是我们永恒的眷恋
2015-11-28 20:54
239 查看
0x00 申明
本文并非水文,不会对Go语言做任何推广性宣传,只是陈述一个事实!0x01 缘起
对 于我们猿(媛)类来说,写出的每一本程序都希望是:对于阅读代码或者维护代码的人是简洁的,对于服务方来说是高效的!简洁和高效这两个词,自从计算机出现 那一天起,一直都是一个至高无上的目标。个人认为面向对象提出来的“可维护性,可扩展性”只是“简洁”的引申义,而“可靠性,稳定性”则是“高效”的引申 义而已。不知道别人是怎么认为的,至少我是一直这么追求的。所以几乎每次打开电脑第一件事都是关注一下业内新闻趣事,总希望能在万花丛中,找出自己欣赏的那一朵
(因为自己渣渣,种不出花来)。大概是2011年,在国内第一次听说Go语言(事实上2009年就诞生了),那个时候四月份平民(真名不知道)他们一帮子
在积极的学习研究Go语言,翻译国外相关文献(一个小插曲,Go语言里的chan关键字,他们本来翻译成频道,我觉得太不形象了,建议修改成通道,后来就
一直延续下来了),我也因为她的显著特性而臣服,把玩了一段时间后,因为那个时候她还没有成熟,标准库功能又弱,加之她“蹩脚”的臭脾气(语法),非得大
家去迎合她,不像C/C++那样,随意摆弄,你要不怕被同事们拍死,完全可以写出只有空格一种字符的程序来!后来就远离了她,直到去年,一次意外的邂逅,
发现她已经出落的如此美丽可人。
0x02 问题
如何才能最大程度上挖掘服务器的处理能力?答案显而易见:并发。并发原语从unix诞生那一天起经过三代进化,分别是多进程->多线程->多协
程,协程概念不清楚的,请自行脑补。如今各大语言工具都支持这个概念,然后实现难易繁简程度各有不同,下文着重比对C/C++与Go之间的差别。
实例:并发100万协程,每个协程处理从0累加至10000,然后阻塞
关注结果:1:并发100W,所需的时间 2:每个协程处理是否正常
(有的童鞋会奇怪为什么每个协程要处理从0累加至10000,有什么意义? 我是这么设计的,个人认为每一个功能从开始到结束,平均大概需要10000个指令周期,这么测,肯定不可能覆盖所有案例,但足以说明一个大概了)
0x03 手起
测试环境: centos 7内核版本号: 3.10.0-229.20.1.el7.x86_64
CPU: 24核 MEM: 32G
Go语言版本号:1.4.2
Go测试代码
package main
import (
"net/http"
"runtime"
"runtime/debug"
"runtime/pprof"
"time"
)
var maxRoutine int = 1000000
var quit = make(chan struct{})
func routine(index int) {
// println("OK,Over I'm routine NO. ", index)
sum := 0
for i := 0; i < 10000; i++ {
sum += i
}
// println("routine No.[", index, "] sum=", sum)
<-quit
}
func handler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
p := pprof.Lookup("goroutine")
p.WriteTo(w, 1)
}
func main() {
println("threads : ", debug.SetMaxThreads(maxRoutine))
runtime.GOMAXPROCS(runtime.NumCPU())
go func() {
tick := time.Tick(10 * time.Second)
for {
select {
case <-tick:
func() {
runtime.GC()
}()
}
}
}()
println("test max routines!")
var i int = 0
begin := time.Now()
for i < maxRoutine {
i++
go routine(i)
}
println("test max routines end. escape time:", time.Now().Sub(begin).Seconds())
// select {}
http.HandleFunc("/", handler)
http.ListenAndServe(":9090", nil)
}
C/C++测试思路简述:
统 计平台CPU核心数,根据核心数开辟等同的线程数,每一个线程绑定在一个CPU核心上,然后再在线程上开辟大量的协程来处理事务。在目前测试环境下,总共 24核,开辟24个线程绑定在24个核上,每个线程开辟4166个协程,第一线程开辟的协程数为:41682,最后让每一个协程处理累加事务,统计测试结 果!(具体代码测试结果,随后补上,这一阵子,有点事,没空整这个)
0x04 刀落
测试结果:
程序运行中协程数:创建100万个协程所需要的时间(单位:秒):
程序创建完成的协程是否仍然正常运行,根据打印出的日志可以看出是正常运行的,因为是并发,量大且凌乱,在这里就没有贴出图来。
说明
本文的一次验证为了下一篇实现C1M(connection one million)级打下基础若清除去运行时监测代码,代码总量仅为50行,流程非常清晰
两版代码相比,难易繁简度立分高下,更重要的C/C++实现的那一版,就看看思路就觉得心力交瘁,尚且不说这里面还有很多需要细致打磨的地方了
0x05 题外
按照现行的主流服务器配置一般情况下,一个功能处理时间都该定界在10微秒以下,上到几十,几百微妙,就该考虑优化了,如果你跟我提建立一个数据库连接就需要几百毫秒了,那这就钻牛角尖纯扯淡了一台服务器的并发数到底能有多大,这个具体数字准确的讲是要依赖于你的应用到底占用了多少资源。在一个服务尚未实现,但又想知道一个概要值参考的
话,可以查看/proc/sys/fs/file-max这个文件里的数值(当然这个值是可以修改的),这个数值的默认值是系统根据标准堆栈数值以及硬件
资源自动计算出的一个数字,实际应用中可以根据具体情况做适当的调整。
0x06 责任
我们应该竭尽全力让各种资源发挥它应有的光芒。相关文章推荐
- n波那契
- svn服务器配置与客户端的使用
- 【小程序】数码平方和
- Shell学习笔记 - 循环语句
- 完美性爱孕育健康宝宝
- Length of Last Word
- QT中QPainterPath类的功能和使用方法
- 引用计数count
- 《实用Common Lisp编程》第三章 实践:简单的数据库
- C++函数
- 133.Oracle数据库SQL开发之 数据库对象——通用调用
- 越过65K方法数的限制编译APP
- Opencv人头跟踪检测
- “滑机约拍”--第一阶段冲刺(4)
- (第八周项目5)计数的模式匹配
- web service axis2常见异常原因
- IE6的重定向页面无法跳转解决
- 二叉排序树的基本操作(建立,中序遍历,查找,删除,插入)
- 【小程序】哈密尔顿距离
- OGNL小结