Purpose: Demo Go Oracle database driver OCI Performance Extensions.
We will do a benchmark and show you the improvement before and after enabling Prefetching rows.
Also use SQL session trace file to prove that Update Batching works, than is insert many rows at one time.
Info:
Update Batching
You can reduce the number of round-trips to the database, thereby improving application performance, by grouping multiple UPDATE, DELETE, or INSERT statements into a single batch and having the whole batch sent to the database and processed in one trip. This is referred to as 'update batching'.
Prefetching rows
This reduces round-trips to the database by fetching multiple rows of data each time data is fetched. The extra data is stored in client-side buffers for later access by the client. The number of rows to prefetch can be set as desired.
...
Code:
// Copyright 2015, Author: Charlie Database Craftsman. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package main demo 2 Oracle OCI Performance Extensions: array interface and Prefetching rows.
- Update Batching
It calls StmtCfg.SetPrefetchRowCount to set Prefetching size for SELECT query.
- Prefetching rows
It is binding slice type data, to pass array to database in single SQL to do Bulk DML, in one context switch.
Notes:
stmtQry.Cfg().SetPrefetchRowCount(uint32(200)) works,
ses.Cfg().StmtCfg.SetPrefetchRowCount(2000) works,
EnvCfg -> SrvCfg are both not work, because code issue, NewStmtCfg() overwrite Env/Srv on session level.
Env.StmtCfg.SetPrefetchRowCount not working.
| Modification History:
| Date Who What
| 11-Jan-2016: Charlie(Yi): Abstract checkErr function,
| 18-Dec-2015: Charlie(Yi): create the package,
*/
package main
import (
"fmt"
"gopkg.in/rana/ora.v3"
)
func main() {
// example usage of the ora package driver
// connect to a server and open a session
env, err := ora.OpenEnv(nil)
defer env.Close()
checkErr(err)
srvCfg := ora.NewSrvCfg()
srvCfg.Dblink = "//localhost/orcl"
srv, err := env.OpenSrv(srvCfg)
defer srv.Close()
checkErr(err)
sesCfg := ora.NewSesCfg()
sesCfg.Username = "scott"
sesCfg.Password = "tiger"
fmt.Println("Session PrefetchRowCount :", sesCfg.StmtCfg.PrefetchRowCount())
sesCfg.StmtCfg.SetPrefetchRowCount(uint32(2000))
ses, err := srv.OpenSes(sesCfg)
fmt.Println("connected")
defer ses.Close()
checkErr(err)
fmt.Println("Session PrefetchRowCount :", ses.Cfg().StmtCfg.PrefetchRowCount())
err = ses.Cfg().StmtCfg.SetPrefetchRowCount(uint32(1000))
checkErr(err)
fmt.Println("Session PrefetchRowCount :", ses.Cfg().StmtCfg.PrefetchRowCount())
stmtTbl, err := ses.Prep(
`declare
l_sql varchar2(32767);
l_cnt pls_integer;
begin
l_sql := 'drop TABLE emp_go purge';
select count(*) into l_cnt from user_tables where table_name='EMP_GO';
if l_cnt > 0 then
execute immediate l_sql;
end if;
end;`)
defer stmtTbl.Close()
checkErr(err)
rowsAffected, err := stmtTbl.Exe()
checkErr(err)
fmt.Println(rowsAffected, " rows Affected. drop table emp_go if exists.")
rowsAffected, err = ses.PrepAndExe("CREATE TABLE emp_go (empno number(5,0), ename VARCHAR2(50))")
checkErr(err)
fmt.Println("table emp_go created")
rowsAffected, err = ses.PrepAndExe("ALTER SESSION SET TRACEFILE_IDENTIFIER='go1'")
checkErr(err)
//SELECT VALUE FROM V$DIAG_INFO WHERE NAME = 'Default Trace File';
rowsAffected, err = ses.PrepAndExe("begin dbms_monitor.session_trace_enable( WAITS=>TRUE, binds=>true); end;")
checkErr(err)
tx1, err := ses.StartTx()
stmt, err := ses.Prep("INSERT INTO emp_go (empno, ename) VALUES (:N1, :C1)")
defer stmt.Close()
checkErr(err)
fmt.Println("Demo bulk/batch insert. Bulk DML with slice (array in Go)")
l_no := make([]int64, 4)
l_name := make([]ora.String, 4)
for n, _ := range l_no {
l_no[n] = int64(n)
l_name[n] = ora.String{Value: fmt.Sprintf("Mr. %v", n)}
fmt.Println(n)
}
rowsAffected, err = stmt.Exe(l_no, l_name)
checkErr(err)
fmt.Println(rowsAffected, " rows add.")
tx1.Commit()
fmt.Println("commit")
fmt.Println("Demo fetch records")
stmtQry, err := ses.Prep("SELECT /* set PrefetchRowCount = 0 */ empno, ename FROM emp_go")
defer stmtQry.Close()
checkErr(err)
err = stmtQry.Cfg().SetPrefetchRowCount(uint32(0))
checkErr(err)
fmt.Println("stmtQry.Cfg().PrefetchRowCount default:", stmtQry.Cfg().PrefetchRowCount())
rset, err := stmtQry.Qry()
checkErr(err)
for rset.Next() {
fmt.Println(rset.Row[0], rset.Row[1])
}
checkErr(rset.Err)
stmtQry, err = ses.Prep("SELECT /* set PrefetchRowCount = 200 */ empno, ename FROM emp_go")
defer stmtQry.Close()
checkErr(err)
err = stmtQry.Cfg().SetPrefetchRowCount(uint32(200))
checkErr(err)
fmt.Println("stmtQry.Cfg().SetPrefetchRowCount(200)", stmtQry.Cfg().PrefetchRowCount())
rset, err = stmtQry.Qry()
checkErr(err)
for rset.Next() {
fmt.Println(rset.Row[0], rset.Row[1])
}
checkErr(rset.Err)
rowsAffected, err = ses.PrepAndExe("begin dbms_monitor.session_trace_disable(); end;")
checkErr(err)
rset, err = ses.PrepAndQry("SELECT VALUE FROM V$DIAG_INFO WHERE NAME = 'Default Trace File'")
for rset.Next() {
fmt.Println(rset.Row[0])
}
}
func checkErr(err error) {
if err != nil {
panic(err)
}
}
Output:
Session PrefetchRowCount : 0
connected
Session PrefetchRowCount : 2000
Session PrefetchRowCount : 1000
0 rows Affected. drop table emp_go if exists.
table emp_go created
Demo bulk/batch insert. Bulk DML with slice (array in Go)
0
1
2
3
4 rows add.
commit
Demo fetch records
stmtQry.Cfg().PrefetchRowCount default: 0
0 Mr. 0
1 Mr. 1
2 Mr. 2
3 Mr. 3
stmtQry.Cfg().SetPrefetchRowCount(200) 200
0 Mr. 0
1 Mr. 1
2 Mr. 2
3 Mr. 3
/home/oracle/app/oracle/diag/rdbms/cdb1/cdb1/trace/cdb1_ora_17092_go1.trc
.
SQL session trace:
tkprof /home/oracle/app/oracle/diag/rdbms/cdb1/cdb1/trace/cdb1_ora_17092_go1.trc rpt.txt
.
TKProf report:
.
Before, PrefetchRowCount = 0.
SELECT /* set PrefetchRowCount = 0 */ empno, ename
FROM emp_go
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 1 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 3 0.00 0.00 0 9 0 4
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 5 0.00 0.00 0 10 0 4
.
After SetPrefetchRowCount = 200.
.
SELECT /* set PrefetchRowCount = 200 */ empno, ename
FROM emp_go
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 1 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 1 0.00 0.00 0 7 0 4
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 3 0.00 0.00 0 8 0 4
.
Bulk INSERT,
.
INSERT INTO emp_go (empno, ename)
VALUES (:N1, :C1)
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 4 43 4
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2 0.00 0.00
Reference:
.
Oracle driver basic, http://mujiang.blogspot.com/2015/12/golang-connect-to-oracle-database.html
driver readme, https://github.com/rana/ora/blob/master/README.md
Performance, http://docs.oracle.com/database/121/JJDBC/oraperf.htm
Tuesday, December 22, 2015
Friday, December 18, 2015
Golang connect to Oracle database
Purpose: setup Go Oracle driver, and a complete code to demo some basic DDL, DML, and bulk batching processing.
Minimum requirements are
- Go 1.3 with CGO enabled,
- a GCC C compiler,
- and Oracle 11g (11.2.0.4.0) or Oracle Instant Client (11.2.0.4.0).
This demo is tested on Go 1.5.2, Oracle Virtual Box, imported OTN_Developer_Day_VM.ova appliance/image file.
** environment settings **
------- Linux ----------
export GOROOT=/usr/local/go
#export GOPATH=/home/oracle/go
export GOPATH=/media/sf_GTD/Project/Go
export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin
mkdir -p $GOPATH/src/github.com/user/hello
cd $GOPATH/src/github.com/user/hello
echo $PATH
echo $GOPATH
# Oracle client driver, environment parameters
# Set the CGO_CFLAGS and CGO_LDFLAGS environment variables to locate the OCI headers and library,
export CGO_CFLAGS=-I$ORACLE_HOME/rdbms/public
export CGO_LDFLAGS="-L$ORACLE_HOME/lib -lclntsh"
-----------
-- install Oracle driver --
go get github.com/rana/ora
-- manual install driver from source zip files --
download source zip files, and extract into $GOPATH/src/gopkg.in/rana/ora.v3/ , or rename ora-master to ora.v3
download address: https://github.com/rana/ora/tree/v3
The files structure will be looks like,
src\gopkg.in\rana\ora.v3\
ora.go
env.go
...
\examples\...
To import this package, add the following line to your code:
import "gopkg.in/rana/ora.v3"
Code:
// Copyright 2015, Author: Charlie Database Craftsman. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package main demo OCI array interface.
It connects to a database, create table, insert data, and query the data.
E:\GTD\Project\Go\src\github.com\user\hello\oracle_demo.go
*/
package main
import (
"fmt"
"gopkg.in/rana/ora.v3"
)
func main() {
// example usage of the ora package driver
// connect to a server and open a session
env, err := ora.OpenEnv(nil)
defer env.Close()
if err != nil {
panic(err)
}
srvCfg := ora.NewSrvCfg()
srvCfg.Dblink = "//localhost/orcl"
srv, err := env.OpenSrv(srvCfg)
defer srv.Close()
if err != nil {
panic(err)
}
sesCfg := ora.NewSesCfg()
sesCfg.Username = "scott"
sesCfg.Password = "tiger"
ses, err := srv.OpenSes(sesCfg)
fmt.Println("connected")
defer ses.Close()
if err != nil {
panic(err)
}
//StmtCfg.PrefetchRowCount = 1000
stmtTbl, err := ses.Prep(
`declare
l_sql varchar2(32767);
l_cnt pls_integer;
begin
l_sql := 'drop TABLE emp_go purge';
select count(*) into l_cnt from user_tables where table_name='EMP_GO';
if l_cnt > 0 then
execute immediate l_sql;
end if;
end;`)
defer stmtTbl.Close()
if err != nil {
panic(err)
}
rowsAffected, err := stmtTbl.Exe()
if err != nil {
panic(err)
}
fmt.Println(rowsAffected, " rows Affected. drop table emp_go if exists.")
rowsAffected, err = ses.PrepAndExe("CREATE TABLE emp_go (empno number(5,0), ename VARCHAR2(50))")
if err != nil {
panic(err)
}
fmt.Println("table emp_go created")
tx1, err := ses.StartTx()
rowsAffected, err = ses.PrepAndExe("delete emp_go")
tx1.Commit()
stmt, err := ses.Prep("INSERT INTO emp_go (empno, ename) VALUES (:N1, :C1)")
defer stmt.Close()
rowsAffected, err = stmt.Exe(uint64(1001), "Charlie")
rowsAffected, err = stmt.Exe(uint64(1002), "Vicky")
if err != nil {
panic(err)
}
fmt.Println(rowsAffected, "add")
tx1.Commit()
tx1.Rollback()
fmt.Println("commit")
fmt.Println("Demo fetch records")
stmtQry, err := ses.Prep("SELECT empno, ename FROM emp_go")
defer stmtQry.Close()
if err != nil {
panic(err)
}
rset, err := stmtQry.Qry()
if err != nil {
panic(err)
}
for rset.Next() {
fmt.Println(rset.Row[0], rset.Row[1])
}
if rset.Err != nil {
panic(rset.Err)
}
}
Output:
$> go run oracle_demo.go
connected
0 rows Affected. drop table emp_go if exists.
table emp_go created
1 add
commit
Demo fetch records
1001 Charlie
1002 Vicky
.
Reference:
https://github.com/rana/ora/blob/master/README.md
http://gopkg.in/rana/ora.v3
Minimum requirements are
- Go 1.3 with CGO enabled,
- a GCC C compiler,
- and Oracle 11g (11.2.0.4.0) or Oracle Instant Client (11.2.0.4.0).
This demo is tested on Go 1.5.2, Oracle Virtual Box, imported OTN_Developer_Day_VM.ova appliance/image file.
** environment settings **
------- Linux ----------
export GOROOT=/usr/local/go
#export GOPATH=/home/oracle/go
export GOPATH=/media/sf_GTD/Project/Go
export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin
mkdir -p $GOPATH/src/github.com/user/hello
cd $GOPATH/src/github.com/user/hello
echo $PATH
echo $GOPATH
# Oracle client driver, environment parameters
# Set the CGO_CFLAGS and CGO_LDFLAGS environment variables to locate the OCI headers and library,
export CGO_CFLAGS=-I$ORACLE_HOME/rdbms/public
export CGO_LDFLAGS="-L$ORACLE_HOME/lib -lclntsh"
-----------
-- install Oracle driver --
go get github.com/rana/ora
-- manual install driver from source zip files --
download source zip files, and extract into $GOPATH/src/gopkg.in/rana/ora.v3/ , or rename ora-master to ora.v3
download address: https://github.com/rana/ora/tree/v3
The files structure will be looks like,
src\gopkg.in\rana\ora.v3\
ora.go
env.go
...
\examples\...
To import this package, add the following line to your code:
import "gopkg.in/rana/ora.v3"
Code:
// Copyright 2015, Author: Charlie Database Craftsman. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package main demo OCI array interface.
It connects to a database, create table, insert data, and query the data.
E:\GTD\Project\Go\src\github.com\user\hello\oracle_demo.go
*/
package main
import (
"fmt"
"gopkg.in/rana/ora.v3"
)
func main() {
// example usage of the ora package driver
// connect to a server and open a session
env, err := ora.OpenEnv(nil)
defer env.Close()
if err != nil {
panic(err)
}
srvCfg := ora.NewSrvCfg()
srvCfg.Dblink = "//localhost/orcl"
srv, err := env.OpenSrv(srvCfg)
defer srv.Close()
if err != nil {
panic(err)
}
sesCfg := ora.NewSesCfg()
sesCfg.Username = "scott"
sesCfg.Password = "tiger"
ses, err := srv.OpenSes(sesCfg)
fmt.Println("connected")
defer ses.Close()
if err != nil {
panic(err)
}
//StmtCfg.PrefetchRowCount = 1000
stmtTbl, err := ses.Prep(
`declare
l_sql varchar2(32767);
l_cnt pls_integer;
begin
l_sql := 'drop TABLE emp_go purge';
select count(*) into l_cnt from user_tables where table_name='EMP_GO';
if l_cnt > 0 then
execute immediate l_sql;
end if;
end;`)
defer stmtTbl.Close()
if err != nil {
panic(err)
}
rowsAffected, err := stmtTbl.Exe()
if err != nil {
panic(err)
}
fmt.Println(rowsAffected, " rows Affected. drop table emp_go if exists.")
rowsAffected, err = ses.PrepAndExe("CREATE TABLE emp_go (empno number(5,0), ename VARCHAR2(50))")
if err != nil {
panic(err)
}
fmt.Println("table emp_go created")
tx1, err := ses.StartTx()
rowsAffected, err = ses.PrepAndExe("delete emp_go")
tx1.Commit()
stmt, err := ses.Prep("INSERT INTO emp_go (empno, ename) VALUES (:N1, :C1)")
defer stmt.Close()
rowsAffected, err = stmt.Exe(uint64(1001), "Charlie")
rowsAffected, err = stmt.Exe(uint64(1002), "Vicky")
if err != nil {
panic(err)
}
fmt.Println(rowsAffected, "add")
tx1.Commit()
tx1.Rollback()
fmt.Println("commit")
fmt.Println("Demo fetch records")
stmtQry, err := ses.Prep("SELECT empno, ename FROM emp_go")
defer stmtQry.Close()
if err != nil {
panic(err)
}
rset, err := stmtQry.Qry()
if err != nil {
panic(err)
}
for rset.Next() {
fmt.Println(rset.Row[0], rset.Row[1])
}
if rset.Err != nil {
panic(rset.Err)
}
}
Output:
$> go run oracle_demo.go
connected
0 rows Affected. drop table emp_go if exists.
table emp_go created
1 add
commit
Demo fetch records
1001 Charlie
1002 Vicky
.
Reference:
https://github.com/rana/ora/blob/master/README.md
http://gopkg.in/rana/ora.v3
Tuesday, December 15, 2015
Golang range and close channel
Code:
package main
import "golang.org/x/tour/tree"
import "fmt"
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
if t == nil {
fmt.Println("Null")
return
}
if t.Left != nil {
Walk(t.Left, ch)
}
ch <- t.Value
fmt.Println("send ", t.Value)
if t.Right != nil {
Walk(t.Right, ch)
}
}
func main() {
ta := tree.New(1)
ca := make(chan int)
go func() {
Walk(ta, ca)
close(ca)
}()
for v := range ca {
fmt.Println("get ", v)
}
}
Comments:
See which line the channel is closed.
package main
import "golang.org/x/tour/tree"
import "fmt"
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
if t == nil {
fmt.Println("Null")
return
}
if t.Left != nil {
Walk(t.Left, ch)
}
ch <- t.Value
fmt.Println("send ", t.Value)
if t.Right != nil {
Walk(t.Right, ch)
}
}
func main() {
ta := tree.New(1)
ca := make(chan int)
go func() {
Walk(ta, ca)
close(ca)
}()
for v := range ca {
fmt.Println("get ", v)
}
}
Comments:
See which line the channel is closed.
Monday, December 14, 2015
Golang Exercise: Equivalent Binary Trees
code:
package main
import "golang.org/x/tour/tree"
import "fmt"
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
if t == nil {
close(ch)
return
}
if t.Left != nil {
Walk(t.Left, ch)
}
ch <- t.Value
//fmt.Println("send ", t.Value)
if t.Right != nil {
Walk(t.Right, ch)
}
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) (b_same bool) {
c1 := make(chan int)
c2 := make(chan int)
b_same = true
go Walk(t1, c1)
go Walk(t2, c2)
for i := 0; i < 10; i++ {
//fmt.Println("get ", <-c1, <-c2)
if <-c1 != <-c2 {
b_same = false
break
}
}
return
}
func main() {
//t1 := tree.New(1)
//fmt.Println(t1)
fmt.Println(Same(tree.New(1), tree.New(1)))
fmt.Println(Same(tree.New(1), tree.New(2)))
}
Output:
http://tour.golang.org/concurrency/8
https://golang.org/doc/play/tree.go
https://github.com/golang/tour/blob/master/tree/tree.go
package main
import "golang.org/x/tour/tree"
import "fmt"
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
if t == nil {
close(ch)
return
}
if t.Left != nil {
Walk(t.Left, ch)
}
ch <- t.Value
//fmt.Println("send ", t.Value)
if t.Right != nil {
Walk(t.Right, ch)
}
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) (b_same bool) {
c1 := make(chan int)
c2 := make(chan int)
b_same = true
go Walk(t1, c1)
go Walk(t2, c2)
for i := 0; i < 10; i++ {
//fmt.Println("get ", <-c1, <-c2)
if <-c1 != <-c2 {
b_same = false
break
}
}
return
}
func main() {
//t1 := tree.New(1)
//fmt.Println(t1)
fmt.Println(Same(tree.New(1), tree.New(1)))
fmt.Println(Same(tree.New(1), tree.New(2)))
}
Output:
true false Program exited.
Function Same, version 2:
func Same(t1, t2 *tree.Tree) (b_same bool) {
c1 := make(chan int)
c2 := make(chan int)
b_same = true
go func() {
Walk(t1, c1)
close(c1)
}()
go func() {
Walk(t2, c2)
close(c2)
}()
for {
v1, ok1 := <-c1
v2, ok2 := <-c2
if !ok1 || !ok2 {
return ok1 == ok2
}
if v1 != v2 {
b_same = false
break
}
}
return
}
Ref:c1 := make(chan int)
c2 := make(chan int)
b_same = true
go func() {
Walk(t1, c1)
close(c1)
}()
go func() {
Walk(t2, c2)
close(c2)
}()
for {
v1, ok1 := <-c1
v2, ok2 := <-c2
if !ok1 || !ok2 {
return ok1 == ok2
}
if v1 != v2 {
b_same = false
break
}
}
return
}
http://tour.golang.org/concurrency/8
https://golang.org/doc/play/tree.go
https://github.com/golang/tour/blob/master/tree/tree.go
Tuesday, December 08, 2015
Golang Exercise: Images
code:
package main
import "golang.org/x/tour/pic"
import "image"
import "image/color"
type Image struct{}
func (p Image) Bounds() image.Rectangle {
return image.Rect(0, 0, 256, 256)
}
func (p Image) ColorModel() color.Model {
return color.RGBAModel
}
func (m Image) At(x, y int) color.Color {
v := uint8(x * y)
return color.RGBA{v, v, 255, 255}
}
func main() {
m := &Image{}
pic.ShowImage(m)
}
Ref:
http://tour.golang.org/methods/16
package main
import "golang.org/x/tour/pic"
import "image"
import "image/color"
type Image struct{}
func (p Image) Bounds() image.Rectangle {
return image.Rect(0, 0, 256, 256)
}
func (p Image) ColorModel() color.Model {
return color.RGBAModel
}
func (m Image) At(x, y int) color.Color {
v := uint8(x * y)
return color.RGBA{v, v, 255, 255}
}
func main() {
m := &Image{}
pic.ShowImage(m)
}
Ref:
http://tour.golang.org/methods/16
Golang Exercise: HTTP Handlers
Code:
package main
import (
"fmt"
"log"
"net/http"
)
type String string
func (h String) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, h)
}
type Struct struct {
Greeting string
Punct string
Who string
}
func (h *Struct) ServeHTTP(w http.ResponseWriter, r*http.Request){
fmt.Fprintf(w, "%v %v %v", h.Greeting, h.Punct, h.Who)
}
func main() {
// your http.Handle calls here
http.Handle("/string", String("I'm a good man."))
http.Handle("/struct", &Struct{"Hello", ":", "Gophers! 你好吗?"})
log.Fatal(http.ListenAndServe("localhost:4000", nil))
}
Call example:
http://localhost:4000/struct
http://localhost:4000/string
Reference:
http://tour.golang.org/methods/14
package main
import (
"fmt"
"log"
"net/http"
)
type String string
func (h String) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, h)
}
type Struct struct {
Greeting string
Punct string
Who string
}
func (h *Struct) ServeHTTP(w http.ResponseWriter, r*http.Request){
fmt.Fprintf(w, "%v %v %v", h.Greeting, h.Punct, h.Who)
}
func main() {
// your http.Handle calls here
http.Handle("/string", String("I'm a good man."))
http.Handle("/struct", &Struct{"Hello", ":", "Gophers! 你好吗?"})
log.Fatal(http.ListenAndServe("localhost:4000", nil))
}
Call example:
http://localhost:4000/struct
http://localhost:4000/string
Reference:
http://tour.golang.org/methods/14
Monday, December 07, 2015
Golang Exercise: rot13Reader
package main
import (
"fmt"
"io"
"os"
"strings"
)
type rot13Reader struct {
r io.Reader
}
func (p rot13Reader) Read(b []byte) (n int, err error) {
n, err = p.r.Read(b)
for i := 0; i < n; i++ {
b[i] = b[i] + 13
if b[i] > 'z' || (b[i] > 'Z' && b[i] < 'a') {
b[i] = b[i] - 26
}
fmt.Printf("b[%v] = %q\n", i, b[i])
}
n = len(b)
return n, err
}
func main() {
s := strings.NewReader("Lbh penpxrq gur pbqr!")
r := rot13Reader{s}
io.Copy(os.Stdout, &r)
}
Output:
Reference:
http://tour.golang.org/methods/12
import (
"fmt"
"io"
"os"
"strings"
)
type rot13Reader struct {
r io.Reader
}
func (p rot13Reader) Read(b []byte) (n int, err error) {
n, err = p.r.Read(b)
for i := 0; i < n; i++ {
b[i] = b[i] + 13
if b[i] > 'z' || (b[i] > 'Z' && b[i] < 'a') {
b[i] = b[i] - 26
}
fmt.Printf("b[%v] = %q\n", i, b[i])
}
n = len(b)
return n, err
}
func main() {
s := strings.NewReader("Lbh penpxrq gur pbqr!")
r := rot13Reader{s}
io.Copy(os.Stdout, &r)
}
Output:
b[0] = 'Y' b[1] = 'o' b[2] = 'u' b[3] = '-' b[4] = 'c' b[5] = 'r' b[6] = 'a' b[7] = 'c' b[8] = 'k' b[9] = 'e' b[10] = 'd' b[11] = '-' b[12] = 't' b[13] = 'h' b[14] = 'e' b[15] = '-' b[16] = 'c' b[17] = 'o' b[18] = 'd' b[19] = 'e' b[20] = '.' You-cracked-the-code.You-cracked-the-code. Program exited.
Reference:
http://tour.golang.org/methods/12
Friday, December 04, 2015
Golang Exercise: Errors
package main
import (
"fmt"
"math"
)
type ErrNegativeSqrt float64
func (e ErrNegativeSqrt) Error() string {
if e < 0 {
return fmt.Sprintf("cannot Sqrt negative number: %v ", float64(e))
}
return ""
}
func Sqrt(x float64) (float64, error) {
if x < 0 {
return x, ErrNegativeSqrt(x)
}
return math.Sqrt(x), ErrNegativeSqrt(x)
}
func main() {
fmt.Println(Sqrt(2))
fmt.Println(Sqrt(-2))
}
Output:
Reference:
http://tour.golang.org/methods/9
import (
"fmt"
"math"
)
type ErrNegativeSqrt float64
func (e ErrNegativeSqrt) Error() string {
if e < 0 {
return fmt.Sprintf("cannot Sqrt negative number: %v ", float64(e))
}
return ""
}
func Sqrt(x float64) (float64, error) {
if x < 0 {
return x, ErrNegativeSqrt(x)
}
return math.Sqrt(x), ErrNegativeSqrt(x)
}
func main() {
fmt.Println(Sqrt(2))
fmt.Println(Sqrt(-2))
}
Output:
1.4142135623730951 -2 cannot Sqrt negative number: -2 Program exited.
Reference:
http://tour.golang.org/methods/9
Thursday, December 03, 2015
Golang Exercise: Stringers
package main
import "fmt"
type IPAddr [4]byte
// TODO: Add a "String() string" method to IPAddr.
func (ip IPAddr) String() string {
var ls_ip string
for i, value := range ip {
//ls_ip = ls_ip + string(i) + ":" + string(int(value)) + "."
switch {
case i == 0:
ls_ip = fmt.Sprintf("%v", value)
default:
ls_ip = fmt.Sprintf("%v.%v", ls_ip, value)
}
}
return ls_ip
}
func main() {
addrs := map[string]IPAddr{
"loopback": {127, 0, 0, 1},
"googleDNS": {8, 8, 8, 8},
}
for n, a := range addrs {
fmt.Printf("%v: %v\n", n, a)
}
}
Output:
Reference:
http://tour.golang.org/methods/7
import "fmt"
type IPAddr [4]byte
// TODO: Add a "String() string" method to IPAddr.
func (ip IPAddr) String() string {
var ls_ip string
for i, value := range ip {
//ls_ip = ls_ip + string(i) + ":" + string(int(value)) + "."
switch {
case i == 0:
ls_ip = fmt.Sprintf("%v", value)
default:
ls_ip = fmt.Sprintf("%v.%v", ls_ip, value)
}
}
return ls_ip
}
func main() {
addrs := map[string]IPAddr{
"loopback": {127, 0, 0, 1},
"googleDNS": {8, 8, 8, 8},
}
for n, a := range addrs {
fmt.Printf("%v: %v\n", n, a)
}
}
Output:
loopback: 127.0.0.1 googleDNS: 8.8.8.8 Program exited.
Reference:
http://tour.golang.org/methods/7
Wednesday, December 02, 2015
Golang Exercise: Slices
Exercise: Slices
ImplementPic
. It should return a slice of length dy
, each element of which is a slice of dx
8-bit unsigned integers. When you run the program, it will display your picture, interpreting the integers as grayscale (well, bluescale) values. The choice of image is up to you. Interesting functions include
(x+y)/2
, x*y
, and x^y
. (You need to use a loop to allocate each
[]uint8
inside the [][]uint8
.) (Use
uint8(intValue)
to convert between types.) .
Solution:
package main
import "golang.org/x/tour/pic"
//import "fmt"
func Pic(dx, dy int) [][]uint8 {
var la_pic [][]uint8
var la_x []uint8
la_x = make([]uint8, dx)
//la_pic = make([][]uint8, 0)
for i := 0; i < dy; i++ {
la_pic = append(la_pic, la_x)
for j := 0; j < dx; j++ {
la_pic[i][j] = uint8((i ^ j))
//fmt.Println(i, j)
}
}
return la_pic
}
func main() {
pic.Show(Pic)
}
Reference:
http://tour.golang.org/moretypes/15
Tuesday, December 01, 2015
Go语言 斐波那契数列 Exercise: Fibonacci closure
My code:
package main
import "fmt"
// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
var ln_prev, ln_current, ln_next int
ln_current = 1
return func() int {
ln_next = ln_current + ln_prev
ln_prev = ln_current
ln_current = ln_next
fmt.Println("log:", ln_prev, ln_current, ln_next)
return ln_next
}
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(i, f())
}
}
Output:
Option 2, Learned from Python way :
package main
import "fmt"
// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
var la_f []int
la_f = make([]int, 2)
la_f = []int{0, 1}
//la_f := []int{0, 1}
var li_idx int
li_idx = 1
return func() int {
la_f = append(la_f, la_f[li_idx]+la_f[li_idx-1])
li_idx = li_idx + 1
fmt.Printf("log: i %d, value %d, pre element %d \n", li_idx, la_f[li_idx], la_f[li_idx-1])
return la_f[li_idx]
}
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Printf("idx: %d, value: %d \n", i, f())
}
}
Output:
log: i 2, value 1, pre element 1
idx: 0, value: 1
log: i 3, value 2, pre element 1
idx: 1, value: 2
log: i 4, value 3, pre element 2
idx: 2, value: 3
log: i 5, value 5, pre element 3
idx: 3, value: 5
log: i 6, value 8, pre element 5
idx: 4, value: 8
log: i 7, value 13, pre element 8
idx: 5, value: 13
log: i 8, value 21, pre element 13
idx: 6, value: 21
log: i 9, value 34, pre element 21
idx: 7, value: 34
log: i 10, value 55, pre element 34
idx: 8, value: 55
log: i 11, value 89, pre element 55
idx: 9, value: 89
Program exited.
package main
import "fmt"
// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
var ln_prev, ln_current, ln_next int
ln_current = 1
return func() int {
ln_next = ln_current + ln_prev
ln_prev = ln_current
ln_current = ln_next
fmt.Println("log:", ln_prev, ln_current, ln_next)
return ln_next
}
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(i, f())
}
}
Output:
log: 1 1 1 0 1 log: 1 2 2 1 2 log: 2 3 3 2 3 log: 3 5 5 3 5 log: 5 8 8 4 8 log: 8 13 13 5 13 log: 13 21 21 6 21 log: 21 34 34 7 34 log: 34 55 55 8 55 log: 55 89 89 9 89 Program exited.
Option 2, Learned from Python way :
package main
import "fmt"
// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
var la_f []int
la_f = make([]int, 2)
la_f = []int{0, 1}
//la_f := []int{0, 1}
var li_idx int
li_idx = 1
return func() int {
la_f = append(la_f, la_f[li_idx]+la_f[li_idx-1])
li_idx = li_idx + 1
fmt.Printf("log: i %d, value %d, pre element %d \n", li_idx, la_f[li_idx], la_f[li_idx-1])
return la_f[li_idx]
}
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Printf("idx: %d, value: %d \n", i, f())
}
}
Output:
log: i 2, value 1, pre element 1
idx: 0, value: 1
log: i 3, value 2, pre element 1
idx: 1, value: 2
log: i 4, value 3, pre element 2
idx: 2, value: 3
log: i 5, value 5, pre element 3
idx: 3, value: 5
log: i 6, value 8, pre element 5
idx: 4, value: 8
log: i 7, value 13, pre element 8
idx: 5, value: 13
log: i 8, value 21, pre element 13
idx: 6, value: 21
log: i 9, value 34, pre element 21
idx: 7, value: 34
log: i 10, value 55, pre element 34
idx: 8, value: 55
log: i 11, value 89, pre element 55
idx: 9, value: 89
Program exited.
Reference:
Subscribe to:
Posts (Atom)