1
0
mirror of https://github.com/golang/go synced 2024-11-21 15:04:44 -07:00

doc: add Google I/O talk and programs

R=r
CC=golang-dev
https://golang.org/cl/1614041
This commit is contained in:
Russ Cox 2010-06-08 16:00:04 -07:00
parent 57a62a8bcb
commit 104cd57c6d
6 changed files with 722 additions and 0 deletions

164
doc/talks/io2010/balance.go Normal file
View File

@ -0,0 +1,164 @@
// Copyright 2010 The Go Authors. 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
import (
"container/heap"
"fmt"
"rand"
"time"
)
const nRequester = 100
const nWorker = 10
// Simulation of some work: just sleep for a while and report how long.
func op() int {
n := rand.Int63n(1e9)
time.Sleep(nWorker * n)
return int(n)
}
type Request struct {
fn func() int
c chan int
}
func requester(work chan Request) {
c := make(chan int)
for {
time.Sleep(rand.Int63n(nWorker * 2e9))
work <- Request{op, c}
<-c
}
}
type Worker struct {
i int
requests chan Request
pending int
}
func (w *Worker) work(done chan *Worker) {
for {
req := <-w.requests
req.c <- req.fn()
done <- w
}
}
type Pool []*Worker
func (p Pool) Len() int { return len(p) }
func (p Pool) Less(i, j int) bool {
return p[i].pending < p[j].pending
}
func (p *Pool) Swap(i, j int) {
a := *p
a[i], a[j] = a[j], a[i]
a[i].i = i
a[j].i = j
}
func (p *Pool) Push(x interface{}) {
a := *p
n := len(a)
a = a[0 : n+1]
w := x.(*Worker)
a[n] = w
w.i = n
*p = a
}
func (p *Pool) Pop() interface{} {
a := *p
*p = a[0 : len(a)-1]
w := a[len(a)-1]
w.i = -1 // for safety
return w
}
type Balancer struct {
pool Pool
done chan *Worker
i int
}
func NewBalancer() *Balancer {
done := make(chan *Worker, nWorker)
b := &Balancer{make(Pool, 0, nWorker), done, 0}
for i := 0; i < nWorker; i++ {
w := &Worker{requests: make(chan Request, nRequester)}
heap.Push(&b.pool, w)
go w.work(b.done)
}
return b
}
func (b *Balancer) balance(work chan Request) {
for {
select {
case req := <-work:
b.dispatch(req)
case w := <-b.done:
b.completed(w)
}
b.print()
}
}
func (b *Balancer) print() {
sum := 0
sumsq := 0
for _, w := range b.pool {
fmt.Printf("%d ", w.pending)
sum += w.pending
sumsq += w.pending * w.pending
}
avg := float64(sum) / float64(len(b.pool))
variance := float64(sumsq)/float64(len(b.pool)) - avg*avg
fmt.Printf(" %.2f %.2f\n", avg, variance)
}
func (b *Balancer) dispatch(req Request) {
if false {
w := b.pool[b.i]
w.requests <- req
w.pending++
b.i++
if b.i >= len(b.pool) {
b.i = 0
}
return
}
w := heap.Pop(&b.pool).(*Worker)
w.requests <- req
w.pending++
// fmt.Printf("started %p; now %d\n", w, w.pending)
heap.Push(&b.pool, w)
}
func (b *Balancer) completed(w *Worker) {
if false {
w.pending--
return
}
w.pending--
// fmt.Printf("finished %p; now %d\n", w, w.pending)
heap.Remove(&b.pool, w.i)
heap.Push(&b.pool, w)
}
func main() {
work := make(chan Request)
for i := 0; i < nRequester; i++ {
go requester(work)
}
NewBalancer().balance(work)
}

View File

@ -0,0 +1,40 @@
// Copyright 2010 The Go Authors. 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
import (
"crypto/aes"
"crypto/block"
"compress/gzip"
"io"
"os"
)
func EncryptAndGzip(dstfile, srcfile string, key, iv []byte) {
r, _ := os.Open(srcfile, os.O_RDONLY, 0)
var w io.Writer
w, _ = os.Open(dstfile, os.O_WRONLY|os.O_CREATE, 0666)
c, _ := aes.NewCipher(key)
w = block.NewOFBWriter(c, iv, w)
w2, _ := gzip.NewDeflater(w)
io.Copy(w2, r)
w2.Close()
}
func DecryptAndGunzip(dstfile, srcfile string, key, iv []byte) {
f, _ := os.Open(srcfile, os.O_RDONLY, 0)
defer f.Close()
c, _ := aes.NewCipher(key)
r := block.NewOFBReader(c, iv, f)
r, _ = gzip.NewInflater(r)
w, _ := os.Open(dstfile, os.O_WRONLY|os.O_CREATE, 0666)
defer w.Close()
io.Copy(w, r)
}
func main() {
EncryptAndGzip("/tmp/passwd.gz", "/etc/passwd", make([]byte, 16), make([]byte, 16))
DecryptAndGunzip("/dev/stdout", "/tmp/passwd.gz", make([]byte, 16), make([]byte, 16))
}

View File

@ -0,0 +1,28 @@
// Copyright 2010 The Go Authors. 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
import (
"crypto/aes"
"crypto/block"
"compress/gzip"
"io"
"os"
)
func EncryptAndGzip(dstfile, srcfile string, key, iv []byte) {
r, _ := os.Open(srcfile, os.O_RDONLY, 0)
var w io.WriteCloser
w, _ = os.Open(dstfile, os.O_WRONLY|os.O_CREATE, 0666)
defer w.Close()
w, _ = gzip.NewDeflater(w)
defer w.Close()
c, _ := aes.NewCipher(key)
io.Copy(block.NewCBCEncrypter(c, iv, w), r)
}
func main() {
EncryptAndGzip("/tmp/passwd.gz", "/etc/passwd", make([]byte, 16), make([]byte, 16))
}

229
doc/talks/io2010/eval1.go Normal file
View File

@ -0,0 +1,229 @@
// Copyright 2010 The Go Authors. 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
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
// Generic expression parser/evaluator
type Value interface {
String() string
BinaryOp(op string, y Value) Value
}
type Parser struct {
precTab map[string]int
newVal func(string) Value
src string
pos int
tok string
}
const alphanum = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
func (p *Parser) stop(c uint8) bool {
switch {
case p.pos >= len(p.src):
return true
case c == '"':
if p.src[p.pos] == '"' {
p.pos++
return true
}
return false
case strings.IndexRune(alphanum, int(c)) >= 0:
return strings.IndexRune(alphanum, int(p.src[p.pos])) < 0
}
return true
}
func (p *Parser) next() {
// skip blanks
for ; p.pos < len(p.src) && p.src[p.pos] <= ' '; p.pos++ {
}
if p.pos >= len(p.src) {
p.tok = ""
return
}
start := p.pos
c := p.src[p.pos]
for p.pos < len(p.src) {
p.pos++
if p.stop(c) {
break
}
}
p.tok = p.src[start:p.pos]
}
func (p *Parser) binaryExpr(prec1 int) Value {
x := p.newVal(p.tok)
p.next()
for prec := p.precTab[p.tok]; prec >= prec1; prec-- {
for p.precTab[p.tok] == prec {
op := p.tok
p.next()
y := p.binaryExpr(prec + 1)
x = x.BinaryOp(op, y)
}
}
return x
}
func Eval(precTab map[string]int, newVal func(string) Value, src string) Value {
var p Parser
p.precTab = precTab
p.newVal = newVal
p.src = src
p.next()
return p.binaryExpr(1)
}
// Command-line expression evaluator
func main() {
r := bufio.NewReader(os.Stdin)
for {
fmt.Printf("> ")
line, err := r.ReadString('\n')
if err != nil {
break
}
fmt.Printf("%s\n", Eval(precTab, trace(newVal), line))
}
}
// Custom grammar and values
var precTab = map[string]int{
"&&": 1,
"||": 2,
"==": 3,
"!=": 3,
"<": 3,
"<=": 3,
">": 3,
">=": 3,
"+": 4,
"-": 4,
"*": 5,
"/": 5,
"%": 5,
}
func newVal(lit string) Value {
x, err := strconv.Atoi(lit)
if err == nil {
return Int(x)
}
b, err := strconv.Atob(lit)
if err == nil {
return Bool(b)
}
return Error(fmt.Sprintf("illegal literal '%s'", lit))
}
type Error string
func (e Error) String() string { return string(e) }
func (e Error) BinaryOp(op string, y Value) Value { return e }
type Int int
func (x Int) String() string { return strconv.Itoa(int(x)) }
func (x Int) BinaryOp(op string, y Value) Value {
switch y := y.(type) {
case Error:
return y
case Int:
switch op {
case "+":
return x + y
case "-":
return x - y
case "*":
return x * y
case "/":
return x / y
case "%":
return x % y
case "==":
return Bool(x == y)
case "!=":
return Bool(x != y)
case "<":
return Bool(x < y)
case "<=":
return Bool(x <= y)
case ">":
return Bool(x > y)
case ">=":
return Bool(x >= y)
}
}
return Error(fmt.Sprintf("illegal operation: '%v %s %v'", x, op, y))
}
type Bool bool
func (x Bool) String() string { return strconv.Btoa(bool(x)) }
func (x Bool) BinaryOp(op string, y Value) Value {
switch y := y.(type) {
case Error:
return y
case Bool:
switch op {
case "&&":
return Bool(x && y)
case "||":
return Bool(x || y)
case "==":
return Bool(x == y)
case "!=":
return Bool(x != y)
}
}
return Error(fmt.Sprintf("illegal operation: '%v %s %v'", x, op, y))
}
func trace(newVal func(string) Value) func(string) Value {
return func(s string) Value {
v := newVal(s)
fmt.Printf("\tnewVal(%q) = %s\n", s, fmtv(v))
return &traceValue{v}
}
}
type traceValue struct {
Value
}
func (x *traceValue) BinaryOp(op string, y Value) Value {
z := x.Value.BinaryOp(op, y.(*traceValue).Value)
fmt.Printf("\t%s.BinaryOp(%q, %s) = %s\n", fmtv(x.Value), op, fmtv(y.(*traceValue).Value), fmtv(z))
return &traceValue{z}
}
func (x *traceValue) String() string {
s := x.Value.String()
fmt.Printf("\t%s.String() = %#v\n", fmtv(x.Value), s)
return s
}
func fmtv(v Value) string {
t := fmt.Sprintf("%T", v)
if i := strings.LastIndex(t, "."); i >= 0 { // strip package
t = t[i+1:]
}
return fmt.Sprintf("%s(%#v)", t, v)
}

261
doc/talks/io2010/eval2.go Normal file
View File

@ -0,0 +1,261 @@
// Copyright 2010 The Go Authors. 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
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
// Generic expression parser/evaluator
type Value interface {
String() string
BinaryOp(op string, y Value) Value
}
type Parser struct {
precTab map[string]int
newVal func(string) Value
src string
pos int
tok string
}
const alphanum = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
func (p *Parser) stop(c uint8) bool {
switch {
case p.pos >= len(p.src):
return true
case c == '"':
if p.src[p.pos] == '"' {
p.pos++
return true
}
return false
case strings.IndexRune(alphanum, int(c)) >= 0:
return strings.IndexRune(alphanum, int(p.src[p.pos])) < 0
}
return true
}
func (p *Parser) next() {
// skip blanks
for ; p.pos < len(p.src) && p.src[p.pos] <= ' '; p.pos++ {
}
if p.pos >= len(p.src) {
p.tok = ""
return
}
start := p.pos
c := p.src[p.pos]
for p.pos < len(p.src) {
p.pos++
if p.stop(c) {
break
}
}
p.tok = p.src[start:p.pos]
}
func (p *Parser) binaryExpr(prec1 int) Value {
x := p.newVal(p.tok)
p.next()
for prec := p.precTab[p.tok]; prec >= prec1; prec-- {
for p.precTab[p.tok] == prec {
op := p.tok
p.next()
y := p.binaryExpr(prec + 1)
x = x.BinaryOp(op, y)
}
}
return x
}
func Eval(precTab map[string]int, newVal func(string) Value, src string) Value {
var p Parser
p.precTab = precTab
p.newVal = newVal
p.src = src
p.next()
return p.binaryExpr(1)
}
// Command-line expression evaluator
func main() {
r := bufio.NewReader(os.Stdin)
for {
fmt.Printf("> ")
line, err := r.ReadString('\n')
if err != nil {
break
}
fmt.Printf("%s\n", Eval(precTab, trace(newVal), line))
}
}
// Custom grammar and values
var precTab = map[string]int{
"&&": 1,
"||": 2,
"==": 3,
"!=": 3,
"<": 3,
"<=": 3,
">": 3,
">=": 3,
"+": 4,
"-": 4,
"*": 5,
"/": 5,
"%": 5,
}
func newVal(lit string) Value {
x, err := strconv.Atoi(lit)
if err == nil {
return Int(x)
}
b, err := strconv.Atob(lit)
if err == nil {
return Bool(b)
}
s, err := strconv.Unquote(lit)
if err == nil {
return String(s)
}
return Error(fmt.Sprintf("illegal literal '%s'", lit))
}
type Error string
func (e Error) String() string { return string(e) }
func (e Error) BinaryOp(op string, y Value) Value { return e }
type Int int
func (x Int) String() string { return strconv.Itoa(int(x)) }
func (x Int) BinaryOp(op string, y Value) Value {
switch y := y.(type) {
case Error:
return y
case String:
switch op {
case "*":
return String(strings.Repeat(string(y), int(x)))
}
case Int:
switch op {
case "+":
return x + y
case "-":
return x - y
case "*":
return x * y
case "/":
return x / y
case "%":
return x % y
case "==":
return Bool(x == y)
case "!=":
return Bool(x != y)
case "<":
return Bool(x < y)
case "<=":
return Bool(x <= y)
case ">":
return Bool(x > y)
case ">=":
return Bool(x >= y)
}
}
return Error(fmt.Sprintf("illegal operation: '%v %s %v'", x, op, y))
}
type Bool bool
func (x Bool) String() string { return strconv.Btoa(bool(x)) }
func (x Bool) BinaryOp(op string, y Value) Value {
switch y := y.(type) {
case Error:
return y
case Bool:
switch op {
case "&&":
return Bool(x && y)
case "||":
return Bool(x || y)
case "==":
return Bool(x == y)
case "!=":
return Bool(x != y)
}
}
return Error(fmt.Sprintf("illegal operation: '%v %s %v'", x, op, y))
}
type String string
func (x String) String() string { return strconv.Quote(string(x)) }
func (x String) BinaryOp(op string, y Value) Value {
switch y := y.(type) {
case Error:
return y
case Int:
switch op {
case "*":
return String(strings.Repeat(string(x), int(y)))
}
case String:
switch op {
case "+":
return x + y
case "<":
return Bool(x < y)
}
}
return Error(fmt.Sprintf("illegal operation: '%v %s %v'", x, op, y))
}
func trace(newVal func(string) Value) func(string) Value {
return func(s string) Value {
v := newVal(s)
fmt.Printf("\tnewVal(%q) = %s\n", s, fmtv(v))
return &traceValue{v}
}
}
type traceValue struct {
Value
}
func (x *traceValue) BinaryOp(op string, y Value) Value {
z := x.Value.BinaryOp(op, y.(*traceValue).Value)
fmt.Printf("\t%s.BinaryOp(%q, %s) = %s\n", fmtv(x.Value), op, fmtv(y.(*traceValue).Value), fmtv(z))
return &traceValue{z}
}
func (x *traceValue) String() string {
s := x.Value.String()
fmt.Printf("\t%s.String() = %#v\n", fmtv(x.Value), s)
return s
}
func fmtv(v Value) string {
t := fmt.Sprintf("%T", v)
if i := strings.LastIndex(t, "."); i >= 0 { // strip package
t = t[i+1:]
}
return fmt.Sprintf("%s(%#v)", t, v)
}

BIN
doc/talks/io2010/talk.pdf Normal file

Binary file not shown.