Golang初步接触

heavydog 发布于2年前
0 条问题

机缘之间,听闻到了Golang。

之前一直没有怎么去深入了解,只知道它是编译型的,自带GC,goroutine以及channel等等。

昨天晚上无聊看看看Golang官网的Language Specification,对Golang有了初步的了解。

个人感觉Golang还是挺好玩的。

Golang主要的优点

Golang是个很有特点的语言,这里是我的个人理解。

特性少,语法简单

因为之前接触的语言也是蛮多的。。python,scala都有见识过。

python的各种内置方法。语法糖真的挺多的。

有些人常说:“人生苦短,我用python”。

不过吃糖的生活固然不错,但是也容易让人味蕾迷失,体会不出其他的味道。

至于scala更是可怕,仅仅语法看了好几天还没看完,看到这个忘记之前的。

Golang的设计更偏向于软件工程,为了“生产”而编码。

所以它本身没有带那么多的语法,上手快,不容易出错。

不错的标准库

以前刚学C时很疑惑:C到底能干嘛啊?为什么我就对着黑框加加减减打印字啊。

标准库东西好少啊,第三方库不会用/不知道用什么好呀。

之后了解到python之后就是因为它丰富的标准库+第三方库而喜欢上了它(不过也有很多麻烦的,例如windows/linux下有些东西不一样,启动速度慢之类的)。

后来又知道了NodeJS,哇,REPL启动的真快,标准库也挺丰富,npm真好用,第三方库真多。

然而=>异步写的好让人烦躁吖,我只是想写个同步的脚本,却必须要异步写(虽然有Promise/Co的稍微解决了这些问题)。

现在又发现了Golang的标准库蛮不错的。

从文件归档、压缩、加密、数据库到数据序列化,字符格式化、校验和以及图形处理、网络库、同步库等应有尽有。

学习时顺便写的小程序

通过Golang把之前用NodeJS实现的多说头像代理又实现了一遍。啧啧,性能没测试。内存占用可比NodeJS少了很多呢。。NodeJS占用30M,Golang版才3M(没有请求时)

package main

import (
    "fmt"
    "io"
    "net/http"
    "net/url"
    "os"
    "sync"
    "time"
)

const (
    prefix  = "http:/"
    timeout = 10
)

var client *http.Client
var bufferPol *sync.Pool

func copyBuffer(dst io.Writer, src io.Reader) (written int64, err error) {
    buf := bufferPol.Get().([]byte)
    defer bufferPol.Put(buf)
    return io.CopyBuffer(dst, src, buf)
}

func proxyHandle(resw http.ResponseWriter, req *http.Request) {
    defer func() {
        if rec := recover(); rec != nil {
            fmt.Fprintf(os.Stderr, "Error: %v", rec)
            http.NotFound(resw, req)
        }
    }()
    reqURL, err := url.Parse(prefix + req.URL.RequestURI())
    if err != nil {
        panic(err)
    }
    fmt.Printf("%v - %v | %v | %v \n", req.Method, reqURL, req.RemoteAddr, time.Now())

    reqHeader := http.Header{
        "Accept":          {"image/*"},
        "Accept-Encoding": {"gzip,deflate,sdcn"},
        "Host":            {reqURL.Host},
        "Referer":         {reqURL.String()},
        "User-Agent":      {req.Header.Get("User-Agent")}}
    request := &http.Request{
        Method: "GET",
        Header: reqHeader,
        URL:    reqURL}
    requestRes, err := client.Do(request)
    if err != nil {
        panic(err)
    }
    if requestRes.StatusCode == 200 {
        header := resw.Header()
        for key, values := range requestRes.Header {
            for _, value := range values {
                header.Add(key, value)
            }
        }
        copyBuffer(resw, requestRes.Body)
    } else {
        panic(requestRes.StatusCode)
    }
}

func main() {
    client = &http.Client{Timeout: time.Second * timeout}
    bufferPol = &sync.Pool{
        New: func() interface{} {
            return make([]byte, 1024*64) //64kb的buffer
        }}

    http.HandleFunc("/", proxyHandle)
    panic(http.ListenAndServe("127.0.0.1:3000", nil))
}

部署

在网上搜到Golang程序的部署到后台执行主要有2种方法:

  1. 通过nohup、screen等实现后台执行Golang程序
  2. 通过python写的Supervisor来管理Golang程序的后台执行

方法1在程序出错退出后没有重启的机制,个人觉得不是特别的好。

方法2要依赖python管理,感觉蛮别扭的。

因为现在各种linux发行版都用了systemd,所以我也选择个使用systemd进行Golang程序的后台管理。

这里贴出来在systemd的配置文件以供参考:

[Unit]
Description=Proxy By Golang
After=network.target remote-fs.target

[Service]
Type=simple
User=http

ExecStart=/srv/go/proxy
ExecReload=kill $MAINPID && /srv/go/proxy
Restart=always
ExecStop=kill $MAINPID

[Install]
WantedBy=multi-user.target

将其保存在 /etc/systemd/system/ 下。。然后就能用 systemctl start|stop|reload 等命令进行操作了。

需要 登录 后回复方可回复, 如果你还没有账号你可以 注册 一个帐号。