测试Go语言的并发性能,利用之前写的接入数据库的代码,实现1000条、10000条数据的更新
插入数据 update_sql.go:
package main
import(
"fmt"
"database/sql"
_ "github.com/lib/pq"
)
var quit chan int = make(chan int)
func checkErr(err error){
if err != nil{
fmt.Println(err)
}
}
func main(){
db,err := sql.Open("postgres","host=localhost port=5432 database= test user=sean password=123")
checkErr(err)
for i:=0; i<10000;i++{
stmt,err := db.Prepare("insert into try values($1,1)")
checkErr(err)
stmt.Exec(i+1)
}
db.Close()
}
不使用并发 original.go
package main
import(
"fmt"
"database/sql"
_ "github.com/lib/pq"
"time"
)
var quit chan int = make(chan int)
func checkErr(err error){
if err != nil{
fmt.Println(err)
}
}
func get_data(id int,db *sql.DB){
rows,err := db.Query("select * from try where ida%4 = $1",id)
checkErr(err)
for rows.Next(){
var IDa int
var IDb int
err = rows.Scan(&IDa,&IDb)
checkErr(err)
if IDb == 1{
//fmt.Println(IDa," ")
stmt,err := db.Prepare("update try set idb = 0 where ida = $1")
checkErr(err)
stmt.Exec(IDa)
}
}
}
func closed(db *sql.DB){
db.Close()
fmt.Println(time.Now())
}
func main(){
db,err := sql.Open("postgres","host=localhost port=5432 database= test user=sean password=123")
checkErr(err)
fmt.Println(time.Now())
get_data(0,db)
get_data(1,db)
get_data(2,db)
get_data(3,db)
defer closed(db)
}
使用并发 parallel.go:
package main
import(
"fmt"
"database/sql"
_ "github.com/lib/pq"
"time"
)
var quit chan int = make(chan int)
func checkErr(err error){
if err != nil{
fmt.Println(err)
}
}
func get_data(id int,db *sql.DB){
rows,err := db.Query("select * from try where ida%4 = $1",id)
checkErr(err)
for rows.Next(){
var IDa int
var IDb int
err = rows.Scan(&IDa,&IDb)
checkErr(err)
if IDb == 1{
//fmt.Println(IDa," ")
stmt,err := db.Prepare("update try set idb = 0 where ida = $1")
checkErr(err)
stmt.Exec(IDa)
}
}
quit <- 0
}
func closed(db *sql.DB){
db.Close()
fmt.Println(time.Now())
}
func main(){
//runtime.GOMAXPROCS(2)
db,err := sql.Open("postgres","host=localhost port=5432 database= test user=sean password=123")
checkErr(err)
fmt.Println(time.Now())
go get_data(0,db)
go get_data(1,db)
go get_data(2,db)
go get_data(3,db)
defer closed(db)
for i := 0; i < 4; i++ {
<- quit
}
}
其中并发必须要quit,不然会报内存错误。
两个程序都只输出程序开始与程序结束的时间,用于对比。
parallel.go和original.go有写四个get_data()函数,不过parallel.go的get_data函数前面会有一个go,这样就自动启动了Go语言的原生并发。在parallel.go中不能直接在函数后close掉数据库的接口,需要调用延时调用函数defer。
关于defer,参考:https://segmentfault.com/a/1190000006823652
parallel.go使用四个goroutine来进行并行,接下来对1000条与10000条数据库更新进行速度对比:
1000 records:
parallel:
2018-03-12 18:27:57.913563077 -0700 PDT
2018-03-12 18:27:58.374490385 -0700 PDT
original:
2018-03-12 18:27:12.652745839 -0700 PDT
2018-03-12 18:27:13.368556225 -0700 PDT
2018-03-12 19:09:04.795747929 -0700 PDT
可以看到,parallel.go显然有加速程序的速度,但效果不是很明显,10000条数据并行会快上5秒左右,不是很令人满意。可能是数据库更新不需要太久的CPU运行时间。那么接下来使用计算词频来测试go并行性能。
采用一篇英文文章进行计算词频,分别写count_original.go和count_parallel.go
count_original.go
package main
import(
"fmt"
"io/ioutil"
"time"
)
func checkErr(err error){
if err!=nil{
fmt.Println(err)
}
}
func main(){
data,err := ioutil.ReadFile("dat")
checkErr(err)
string_dat := string(data)
fmt.Println(time.Now())
for i:=0; i<50000; i++{
mySlice := make([]string,0)
myWord := make([]byte,0)
for i:=0; i
这部分代码直接暴力检索50000次这篇文章的词频。
count_parallel.go
package main
import(
"fmt"
"io/ioutil"
"time"
)
func checkErr(err error){
if err!=nil{
fmt.Println(err)
}
}
func count_words(string_dat string){
for i:=0; i<10000; i++{
mySlice := make([]string,0)
myWord := make([]byte,0)
for i:=0; i
parallel分为五个并发,每个各一万次检索。显然两个代码的工作量是一模一样的。
然后速率对比为:
ubuntu@ubuntu:~/Desktop$ go run count_parallel.go
2018-03-12 21:24:16.411178996 -0700 PDT
2018-03-12 21:24:16.411366576 -0700 PDT
ubuntu@ubuntu:~/Desktop$ go run count_original.go
2018-03-12 21:24:38.096900407 -0700 PDT
2018-03-12 21:24:47.133811829 -0700 PDT
显然,使用了goroutine的代码运行速度要快上许多。
综合上述,可以看出Go语言的并发易于实现,性能优越。至于编译可执行文件,可以使用go build xxx.go,可以直接得到可执行文件。