Go语言 并发测试

测试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


10000 records:
first time:
parallel
2018-03-12 18:31:00.611855928 -0700 PDT
2018-03-12 18:31:09.662489605 -0700 PDT
original:
2018-03-12 18:32:11.10978443 -0700 PDT
2018-03-12 18:32:25.509550917 -0700 PDT

second time:
parallel
2018-03-12 18:37:26.943626262 -0700 PDT
2018-03-12 18:37:37.14694255 -0700 PDT
original:
2018-03-12 18:38:05.762992124 -0700 PDT
2018-03-12 18:38:20.813318098 -0700 PDT

third time:
parallel:
2018-03-12 19:09:38.211511757 -0700 PDT
2018-03-12 19:09:48.770161877 -0700 PDT
original:
2018-03-12 19:08:49.992954117 -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,可以直接得到可执行文件。


你可能感兴趣的:(Go语言 并发测试)