fizzbuzz(6), with 'knock-service'

package main

import (
    "flag"
    "fmt"
    "net/http"
    "strconv"
    "sync"
)

var (
    vol = flag.Int("v", 100, "volume")
    max = flag.Int("m", 10000, "send numbers")
)

type msg struct {
    Q int
    A int
}

type comm struct {
    Sch chan msg
    Rch chan msg
}

type reply struct {
    Comm chan *comm
}

var (
    poolSub chan reply = make(chan reply)
    poolAdd chan *comm = make(chan *comm)
)

var (
    standbyPub chan reply = make(chan reply)
    standbyOk  chan *comm = make(chan *comm)
)

func save() {
    var (
        pool    []*comm = make([]*comm, 0, *vol)
        standby []*comm = make([]*comm, 0, *vol)
    )
    for {
        select {
        case x := <-poolSub:
            last := len(pool) - 1
            if last > 0 {
                x.Comm <- pool[last]
                pool = pool[:last]
            } else {
                x.Comm <- nil
            }

        case x := <-poolAdd:
            standby = append(standby, x)

        case y := <-standbyPub:
            last := len(standby) - 1
            if last > 0 {
                y.Comm <- standby[last]
                standby = standby[:last]
            } else {
                y.Comm <- nil
            }

        case y := <-standbyOk:
            pool = append(pool, y)
        }
    }
}

func set() func(func(msg) msg) {
    var comms []comm
    for i := 0; i < *vol; i++ {
        comms = append(comms, comm{})
        comms[i].Sch = make(chan msg)
        comms[i].Rch = make(chan msg)
    }

    return func(g func(x msg) msg) {
        for i := 0; i < *vol; i++ {
            i := i
            rch := comms[i].Sch
            sch := comms[i].Rch
            poolAdd <- &comms[i]

            go func() {
                for {
                    x := <-rch
                    sch <- g(x)
                    poolAdd <- &comms[i]
                }
            }()
        }
    }
}

const (
    FIZZBUZZ = iota
    FIZZ
    BUZZ
    NOTFIZZBUZZ
)

func init() {
    flag.Parse()
    go save()

    f := set()
    g := func(m msg) msg {
        x := m.Q
        switch {
        case x%15 == 0:
            m.A = FIZZBUZZ
        case x%3 == 0:
            m.A = FIZZ
        case x%5 == 0:
            m.A = BUZZ
        default:
            m.A = NOTFIZZBUZZ
        }
        return m
    }
    f(g)
}

var ctrl chan struct{} = make(chan struct{})

func let() {
    close(ctrl)
}

func send(g func() msg) {
    for i := 0; i < *max; i++ {
        go func() {
            res := make(chan *comm)
            <-ctrl
            for {
                poolSub <- reply{res}
                c := <-res

                if c != nil {
                    c.Sch <- g()
                    break
                }
            }
            close(res)
        }()
    }
}

// done is for waiting all-received-timing
var done chan struct{} = make(chan struct{})

func wait() {
    <-done
}

func recv(f func(chan msg) error) {
    var wg sync.WaitGroup
    wg.Add(*max)
    go func() {
        for {
            res := make(chan *comm)
            standbyPub <- reply{res}
            c := <-res
            if c != nil {
                go func() {
                    f(c.Rch)
                    wg.Done()
                }()
                standbyOk <- c
            }
            close(res)
        }
    }()
    wg.Wait()
    close(done)
}

func main() {
    // "Knock-service"
    // GET http://localhost:8080/knock?k=n
    // then n'th fizzbuzz execute.
    f := func() func() msg {
        var n int
        knock := make(chan struct{})
        http.HandleFunc("/knock", func(w http.ResponseWriter, r *http.Request) {
            k := r.URL.Query().Get("k")
            if rep, err := strconv.Atoi(k); err == nil {
                for ; rep > 0; rep-- {
                    knock <- struct{}{}
                }
            } else {
                knock <- struct{}{}
            }
            fmt.Fprint(w, http.StatusOK)
        })
        go http.ListenAndServe(":8080", nil)

        return func() msg {
            <-knock
            n++
            return msg{Q: n}
        }
    }
    // send and g sends numbers to setted goroutines
    g := f()
    go send(g)

    // recv and h processes the results from setted goroutines
    h := func(ch chan msg) error {
        m := <-ch

        var ans string
        switch m.A {
        case FIZZBUZZ:
            ans = "fizzbuzz"
        case FIZZ:
            ans = "fizz"
        case BUZZ:
            ans = "buzz"
        case NOTFIZZBUZZ:
            ans = "-"
        }

        fmt.Println(m.Q, ":", ans)
        return nil
    }
    go recv(h)

    let()  // start
    wait() // wait
}

fizzbuzz(6)

package main

import (
    "flag"
    "fmt"
    "sync"
)

var (
    vol = flag.Int("v", 100, "volume")
    max = flag.Int("m", 10000, "send numbers")
)

type msg struct {
    Q int
    A int
}

type comm struct {
    Sch chan msg
    Rch chan msg
}

type reply struct {
    Ch chan *comm
}

var (
    poolSub chan reply = make(chan reply)
    poolAdd chan *comm = make(chan *comm)
)

var (
    standbyPub chan reply = make(chan reply)
    standbyOk  chan *comm = make(chan *comm)
)

func save() {
    var pool []*comm = make([]*comm, 0, *vol)
    var standby []*comm = make([]*comm, 0, *vol)
    for {
        select {
        case x := <-poolSub:
            last := len(pool) - 1
            if last > 0 {
                x.Ch <- pool[last]
                pool = pool[:last]
            } else {
                x.Ch <- nil
            }

        case x := <-poolAdd:
            standby = append(standby, x)

        case y := <-standbyPub:
            last := len(standby) - 1
            if last > 0 {
                y.Ch <- standby[last]
                standby = standby[:last]
            } else {
                y.Ch <- nil
            }

        case y := <-standbyOk:
            pool = append(pool, y)
        }
    }
}

func set() func(func(msg) msg) {
    var comms []comm
    return func(g func(x msg) msg) {
        for i := 0; i < *vol; i++ {
            comms = append(comms, comm{})
            comms[i].Sch = make(chan msg)
            comms[i].Rch = make(chan msg)
        }

        for i := 0; i < *vol; i++ {
            i := i
            rch := comms[i].Sch
            sch := comms[i].Rch
            poolAdd <- &comms[i]

            go func() {
                for {
                    x := <-rch
                    sch <- g(x)
                    poolAdd <- &comms[i]
                }
            }()
        }
    }
}

const (
    FIZZBUZZ = iota
    FIZZ
    BUZZ
    NOTFIZZBUZZ
)

func init() {
    flag.Parse()
    go save()

    f := set()
    g := func(m msg) msg {
        x := m.Q
        switch {
        case x%15 == 0:
            m.A = FIZZBUZZ
        case x%3 == 0:
            m.A = FIZZ
        case x%5 == 0:
            m.A = BUZZ
        default:
            m.A = NOTFIZZBUZZ
        }
        return m
    }
    f(g)
}

var ctrl chan struct{} = make(chan struct{})

func let() {
    close(ctrl)
}

func send(g func() msg) {
    for i := 0; i < *max; i++ {
        go func() {
            res := make(chan *comm)
            <-ctrl
            for {
                poolSub <- reply{res}
                c := <-res

                if c != nil {
                    c.Sch <- g()
                    break
                }
            }
            close(res)
        }()
    }
}

// done is for waiting all-received-timing
var done chan struct{} = make(chan struct{})

func wait() {
    <-done
}

func recv(f func(chan msg) error) {
    var wg sync.WaitGroup
    wg.Add(*max)
    go func() {
        for {
            res := make(chan *comm)
            standbyPub <- reply{res}
            c := <-res
            if c != nil {
                go func() {
                    f(c.Rch)
                    wg.Done()
                }()
                standbyOk <- c
            }
            close(res)
        }
    }()
    wg.Wait()
    close(done)
}

func main() {
    // send and g sends numbers to setted goroutines
    f := func() func() msg {
        var n int
        return func() msg {
            n++
            return msg{Q: n}
        }
    }
    g := f()
    go send(g)

    // recv and h processes the results from setted goroutines
    h := func(ch chan msg) error {
        m := <-ch

        var ans string
        switch m.A {
        case FIZZBUZZ:
            ans = "fizzbuzz"
        case FIZZ:
            ans = "fizz"
        case BUZZ:
            ans = "buzz"
        case NOTFIZZBUZZ:
            ans = "-"
        }

        fmt.Println(m.Q, ":", ans)
        return nil
    }
    go recv(h)

    let()  // start
    wait() // wait
}

mecabのbuild

repository がgithubに移行。 ipadic をconfigureする時に、--with-mecab-config="xxx"が必要。

$ git clone https://github.com:taku910/mecab.git
$ cd mecab/mecab
$ ./configure --with-charset=utf8 --enable-utf8-only
$ make
$ make check
$ sudo make install

$ cd ../..
$ wget http://sourceforge.net/projects/mecab/files/mecab-ipadic/2.7.0-20070801/mecab-ipadic-2.7.0-20070801.tar.gz
$ tar zxvf mecab-ipadic-2.7.0-20070801.tar.gz
$ cd mecab-ipadic-2.7.0-20070801

$ which mecab-config
/usr/local/bin/mecab-config

$ ./configure --with-mecab-config=/usr/local/bin/mecab-config --with-charset=utf8
$ make
$ sudo make install
import (
  "io"
  "os/exec"
)

func mecabCmd(w io.Writer, r io.Reader, dic string) error {
  cmd := exec.Command("mecab", "-d", dic)
  cmd.Stdin = r
  cmd.Stdout = w
  err := cmd.Run()
  if err != nil {
    return err 
  }
  return nil
}

Goのloop

loopのvariable

for _, v := range items {
  v := v
  go func(){
    process(v)
  }()
}
for _, v := range items {
  go func(v type) {
    process(v)
  }(v)
}

loopとwait group

var wg sync.WaitGroup
for _, v := range items {
   v := v
   wg.Add(1)
   go func(){
      process(v)
      wg.Done()
   }()
}
wg.Wait()

loopとwaitgroupとchannel

var wg sync.WaitGroup
ch := make(chan type)
for  _, v := range items {
  wg.Add(1)
  go func(v type) {
    defer wg.Done()
    res, _ := process(v)
    ch <- res
  }(v)
}
go func(){
  wg.Wait()
  close(ch)
}()
for res := range {
  process(res)
}

loopとwaitgroupとchannel、semaphore

var wg sync.WaitGroup
ch := make(chan type)
sem := make(chan struct{}, num)
for  _, v := range items {
  wg.Add(1)
  go func(v type) {
    defer wg.Done()
    sem <- struct{}{}
    res, _ := process(v)
    <-sem
    ch <- res
  }(v)
}
go func(){
  wg.Wait()
  close(ch)
}()
for res := range {
  process(res)
}

C source files not allowed when not using cgo or SWIG: sqlite3-binding.c

ubuntu14.04

sudo apt-get install g++-multilib

and,

Explicity 'CGO_ENABLE=1'

CGO_ENABLED=1 GOARCH=amd64 GOOS=linux go build -o XXX

ubuntuも32bitなくなるかもしれないし、つらい。

ていうか、64bit、、、Raspi3ほっしい。

コアほしい。