2013年8月20日 星期二

一個 golang 的非同步 stdin 的範例

    這篇文章只是一個簡單的例子,示範 golang 的 go 與 select 用法。 golang 原生就支援多序了,因此可以寫起來很簡潔。



package main

import (
    "fmt"
    "time"
    "math/rand"
    "strconv"
)

func main(){
    timeout := make(chan int, 1)
    userChan := make(chan string, 1)
    quitChan := make(chan int, 1)
    var userAnswerStr string
    var answer int
    var a, b int
    rand.Seed(time.Now().UTC().UnixNano())
    timeoutFunc := func(quit chan int){
        timeoutChan := make(chan int, 1)
        go func(){
            time.Sleep(5 * time.Second)
            timeoutChan <- 1
        }()
        select{
        case <-quit:
            return
        case <- timeoutChan:
            timeout <- 1
        }
    }
    inputFunc := func(){
        var input string
        _, err := fmt.Scanf("%s", &input)
        if err != nil{
        }
        userChan <- input
    }
    go inputFunc()
    for{
        a =  rand.Int() % 100
        b =  rand.Int() % 100
        answer = a + b
        fmt.Printf("%d + %d = %d\n", a, b, answer)
        go timeoutFunc(quitChan)

        select{
        case userAnswerStr =<- userChan:
            userAnswer, err := strconv.Atoi(userAnswerStr)
            if err != nil{
                fmt.Println("Error")
                fmt.Printf("Input is %s\n", userAnswerStr)
            }else{
                if userAnswer == answer{
                    fmt.Println("yes\n")
                }else{
                    fmt.Println("no\n")
                }
            }
            go inputFunc()
            quitChan <- 1
        case <- timeout:
            fmt.Println("timeout")
        }
    }
}

    go 這個關鍵字後面接一個 statement。表示開一個新的 Goroutines (可以達到 thread 的功能), chan 就類似 queue。select 敘述則會等待,直到有個 chan 有東西,則繼續執行。想知道確切的用法,請參考 http://golang.org/doc/effective_go.html

    golang 支援 closures,也可以讓程式變簡潔。不必還要傳參數進去,也減少暴露沒必要的函數。不過現在很多程式語言都支援 closures 就是了, python, ruby, javascript等語言。

沒有留言:

張貼留言