Why PythonPython是一個很酷的編程語言,它極致的簡潔,極易上手,我們可以用它來做云計算、大數(shù)據(jù)分析,運維自動化,當(dāng)然還可以寫網(wǎng)站、做爬蟲。 Why not Python但我們也清楚地知道它會受限于GIL,還好我們有g(shù)event,我們可以很愉快地monkey.patch_all(),然后用greenlet來處理,但即使這樣,在并發(fā)量極高的情況下,它的效率就有些令我們擔(dān)心了。 Golang or OpenResty當(dāng)我們開始關(guān)注高性能高并發(fā)服務(wù)端實現(xiàn)的時候,我們自然而然地將目光轉(zhuǎn)向一些現(xiàn)代化的技術(shù),這就是Golang和OpenResty,當(dāng)然他們的核心都是將IO復(fù)用與協(xié)程進(jìn)行有機的融合,但卻有著截然不同的表現(xiàn)風(fēng)格。如果你要問我更喜歡哪個,我會說both。當(dāng)然下文我會介紹Golang。 Golang我的哲學(xué)是,要熟悉一個編程語言,就是要從最簡單的代碼開始寫起來。百試不爽。 package main //包聲明
import 'fmt' //導(dǎo)入包
func main() {
fmt.Println('Hello, 世界')
} 用golang寫個mongodb的api出來。 package main
import (
'encoding/json'
'github.com/cloudflare/conf'
'gopkg.in/macaron.v1' //Web框架Macaron
'labix.org/v2/mgo'
'log'
'net/http'
'os'
'strconv'
)
// 聲明包級別的變量
var (
MONGO_URL string
MONGO_DB string
)
// 包初始化函數(shù)init
func init() {
c, err := conf.ReadConfigFile('config.conf') //配置文件見config.conf
e(err, true)
MONGO_URL = c.GetString('MONGO_URL', '127.0.0.1:27017')
MONGO_DB = c.GetString('MONGO_DB', 'test')
}
func e(err error, fatal bool) (ret bool) {
if err != nil {
log.Println(err.Error())
if fatal {
os.Exit(1)
}
return true
} else {
return false
}
}
func main() {
ms, err := mgo.Dial(MONGO_URL)
e(err, true)
defer ms.Close() //延遲到函數(shù)將要返回時執(zhí)行
ms.SetMode(mgo.Monotonic, true)
mdb := ms.DB(MONGO_DB)
m := macaron.Classic()
m.Map(mdb)
m.Get('/', func(mdb *mgo.Database) string {
names, err := mdb.CollectionNames()
e(err, false)
body, err := json.Marshal(names)
e(err, false)
return string(body)
})
m.Get('/:col', func(mdb *mgo.Database, ctx *macaron.Context, req *http.Request) string {
req.ParseForm()
mcol := mdb.C(ctx.Params(':col'))
limit := 20
offset := 0
if t := req.FormValue('limit'); t != '' {
limit, err = strconv.Atoi(t)
e(err, false)
}
if t := req.FormValue('offset'); t != '' {
offset, err = strconv.Atoi(t)
e(err, false)
}
total_count, err := mcol.Find(nil).Count()
e(err, false)
items := []map[string]interface{}{}
iter := mcol.Find(nil).Skip(offset).Limit(limit).Iter()
for {
item := map[string]interface{}{}
if iter.Next(&item) {
// item := map[string]interface{}{} 不能寫在這里,因為Map是引用類型
items = append(items, item)
} else {
break
}
}
dict := map[string]interface{}{
'meta': map[string]int{'total_count': total_count, 'offset': offset, 'limit': limit},
'data': items,
'msg': 'success',
'code': 0,
}
body, err := json.Marshal(dict)
e(err, false)
return string(body)
})
m.Run()
} config.conf MONGO_URL=127.0.0.1:27017
MONGO_DB=devmgmt 繼續(xù)看一個Kill MySQL慢查詢的小工具。 package main
import (
'database/sql'
'fmt'
_ 'github.com/go-sql-driver/mysql' //匿名導(dǎo)入
'io/ioutil'
'log'
'os'
'regexp'
'strings'
'time'
)
func e(err error, fatal bool) (ret bool) {
if err != nil {
log.Println(err.Error())
if fatal {
os.Exit(1)
}
return true
} else {
return false
}
}
var (
DBS = map[string]string{}
dbs = map[string]*sql.DB{}
)
func init() {
log.SetFlags(log.Flags() | log.Lshortfile)
bytes, err := ioutil.ReadFile('config.conf') //見config.conf
e(err, true)
str := string(bytes)
lines := strings.Split(str, '\n')
reg, err := regexp.Compile(`\s `)
e(err, true)
for num, line := range lines {
if line == '' {
continue
}
if strings.HasPrefix(line, '#') {
continue
}
fields := reg.Split(line, -1)
if len(fields) != 2 {
log.Printf('Line %d is not match the config format.', num 1)
continue
}
dbname := fields[0]
dburi := fields[1]
DBS[dbname] = dburi
dbs[dbname] = init_db(dburi)
}
}
func init_db(uri string) *sql.DB {
db, err := sql.Open('mysql', uri)
e(err, true)
return db
}
func task(dbname string, db *sql.DB) {
for {
rows, err := db.Query('select id,info,time from information_schema.PROCESSLIST where time > 5 and command = 'Query';')
if err != nil {
log.Println(err.Error())
dbs[dbname] = init_db(DBS[dbname])
task(dbname, dbs[dbname])
break
}
for rows.Next() {
var id string
var info string
var time string
err = rows.Scan(&id, &info, &time)
if err != nil {
log.Println(err.Error())
} else {
log.Printf('[FOUND SQL]: '%s'@'%s' (ConnectionId: %s, Time: %s)', info, dbname, id, time)
_, err := db.Exec(fmt.Sprintf('kill %s;', id))
if err != nil {
log.Println(err.Error())
} else {
log.Printf('[KILLED SQL]: '%s'@'%s' (ConnectionId: %s, Time: %s)', info, dbname, id, time)
}
}
}
time.Sleep(1 * time.Second)
}
}
func main() {
for dbname, db := range dbs {
go task(dbname, db) //用go關(guān)鍵字創(chuàng)建goroutine
}
c := make(chan int)
<-c // 阻塞main goroutine
} config.conf # 配置文件以#開頭的為注釋
# 配置行 為 數(shù)據(jù)庫昵稱和數(shù)據(jù)庫uri的組合,中間以若干空白為分隔
db1(127.0.0.1) root:root.com@tcp(127.0.0.1:3306)/mysql?charset=utf8
vhost1 ds:root.com@tcp(192.2.3.143:3306)/mysql?charset=utf8 看個panic和recover的代碼片段。 package main
import (
'fmt'
)
func PanicAndRecover(input string) (res string) {
defer func() {
if p := recover(); p != nil { //從panic中恢復(fù)
fmt.Printf('%T, %#v\n', p, p)
res = 'error' //defer中修改函數(shù)的返回值
}
}()
panic(input) //觸發(fā)panic
return 'normal'
}
func main() {
err := PanicAndRecover('ds')
fmt.Println(err)
} 面向?qū)ο蟮睦印?br>https://github.com/Hevienz/go-mongo package go_mongo
import (
'gopkg.in/mgo.v2'
'log'
'os'
)
type Mongo struct{
session *mgo.Session
}
func New(murls string) *Mongo {
ms, err := mgo.Dial(murls)
if err != nil {
log.Printf('mgo.Dial, %s\n', err)
os.Exit(1)
}
return &Mongo{session: ms}
}
func (self *Mongo) Insert(mdbs string, mcols string, docs ...interface{}) error { //*Mongo類型的方法,docs是可變參數(shù)
mdb := self.session.DB(mdbs)
mcol := mdb.C(mcols)
return mcol.Insert(docs...)
} 在main.go中使用包github.com/Hevienz/go-mongo。 package main
import (
'github.com/Hevienz/go-mongo'
'github.com/Hevienz/go-utils' //下文介紹
'log'
)
func main() {
doc := map[string]interface{}{'ds': 'cc'}
m := go_mongo.New('127.0.0.1:27017')
go_utils.Dir(m) //調(diào)用go_utils包的Dir方法
err := m.Insert('test', 'ds', doc)
if err != nil {
log.Println(err)
}
} 用反射實現(xiàn)類似Python中的build-in函數(shù)dir。 package go_utils
import (
'reflect' //導(dǎo)入反射包
'fmt'
'strings'
)
func Dir(x interface{}) {
v := reflect.ValueOf(x)
t := v.Type()
fmt.Printf('type %s\n', t)
for i := 0; i < v.NumMethod(); i {
methType := v.Method(i).Type()
fmt.Printf('func (%s) %s%s\n', t, t.Method(i).Name,
strings.TrimPrefix(methType.String(), 'func'))
}
} 其它重要的特性包括:接口,類型斷言,類型分支,channel,互斥鎖等,此處不再介紹。 |
|