« 分享文件服务 | 返回首页 | Go 语言初学实践(2) »

Go 语言初学实践(1)

今天想到个点子,做一个文件传输的服务。我觉得是个很简单的东西,可以满足自己的需要。写了篇 blog 理了一下思路。不过,如果光这口头说说其实是很偷懒的一件事情。我觉得,大部分网络产品弄个专职的所谓产品经理,光说想要啥自己不动手实现一下(或是不会写程序),是件极其不靠谱的事情。

说些啥都不如自己动手做出来。最近半年我好象老干这种事情,光说不练。最近一个月也没写什么大篇幅的代码,再老是这样,肯定会手生的。管它好不好,动手实现才是王道。正好最近想折腾一下 Go 语言,那么就拿 Go 来写写看吧。

新语言还是不熟的,老要翻资料。不过这也是学习的必经之路。晚上写了几百行程序,还经常出现语法错误,速度很慢,不过慢慢就有状态了。

在这里,就随便贴一小段代码,算是一点点初学实践吧。

这里有一个小需求,希望有一个 Go 函数,每次调用一次,就返回一个由英文大写字母构成的随机字符串。(用来生成一个短网址)那么用 Go 怎么实现好呢?

package main

import "fmt"
import "rand"

var keyGen func() string

func init() {
    keys := make(chan string)
    go func() {
        for {
            var buf [8]byte
            for i:=0 ; i<8 ; i++ {
                buf[i] = byte(rand.Intn(26)) + byte('A')
            }
            keys <- string(buf[:])
        }
    } ()
    keyGen = func() string {
        return <-keys
    }
}

func main() {
    fmt.Println(keyGen())
    fmt.Println(keyGen())
    fmt.Println(keyGen())
}

这是我的一个范例程序,不知道是否符合 Go 语言的惯用法。

这里使用了一个 goroutine ,不断的产生随机串,送去一个 chan 。然后 keyGen 是由 init 函数初始化的 closure ,它每次从 chan 里读到一个生成好的串。

这种实现手法,应该算是 go 程序和 C/C++ 程序最大的不同吧。如果用 C 实现,几乎不会有人采用多线程方案来生成它们,但是 go 里使用 goroutine 却是一件很自然的事情。嗯,我是这么理解的。

Comments

弱弱地问一下,大神您是完全转入go开发了吗?

go确实是一门很不错的语言, 我使用golang也有1年多了, 这种写法虽然优雅, 但是在并发量大的服务中, 会导致多个goroutine抢占这个随机数生成的channel 导致性能低下

想到那句:
show me the code

我看Go也不久,不确定常用写法应该如何。但是看Effective Go和Go Tutorial里的代码,感觉应该init直接返回chan string就好了,不需要var keyGen func() string。

试着用下,~

这个都是代码啊

看了你上面一篇博客。觉得直接根据文件生产md5串做URI更简单。

这里为啥goroutine,如果仅仅是为了生成不一样key,是不是通过rand+一些时间相关的串即可?

呵呵~~~对于PM,我和你的态度一样啊

往后写的话,还需要在生成 key 的 goroutine 里做一些管理工作。比如不生成相同的,管理 key 的映射表等等。

对于 key 的池子来说是有状态的。

我认为,大多数情况下,使用 buffer 都是没有必要的。

感觉你在不务正业

对于这种无状态的功能, 最好不要硬用channel 和 goroutine, c 程序中有谁这样用定要被骂. 当然练习除外.

如果生成随机串的过程很慢, 出于性能的考虑, 那也要使用带 buffer 的channel, 并且启动时设置runtime.GOMAXPROCS(N).

产品经理被赤裸裸的鄙视了。。呵呵

用时间初始化 rand 序列放在哪里没有必要。如果整个软件需要一个不定的序列,那么应该由软件启动模块来做这件事情,至少不应该由 keygen 子模块来做。

用一个 goroutine 仅仅来生成随机数列,我认为是一种错误使用。如果随机数列是一个较大代价的操作,那么 go routine 的使用应该放在 rand 函数实现内部。是由库提供者来考量这个策略的。

package main

import (
"fmt"
"time"
"rand"
)

var keys chan byte

func init() {
rand.Seed(time.Nanoseconds())
keys = make(chan byte)
go func() {
for {
keys <- byte(rand.Intn(26)+65)
}
}()
}

func MakeKeyGen(n int) (func() string) {
return func() string{
buf := make([]byte, n)
for i:=0;i<n;i++{
buf[i] = <-keys
}
return string(buf)
}
}

func main() {
fmt.Println(MakeKeyGen(8)())
fmt.Println(MakeKeyGen(5)())
fmt.Println(MakeKeyGen(3)())
}

你忘了初始化seed……
另外试着修改了下……

Post a comment

非这个主题相关的留言请到:留言本