每日新闻

每日新闻

GoCN每日新闻资讯
有问必答

有问必答

Go相关的问题,技术相关的问题
文章分享

文章分享

技术文章分享,让知识传播给更多的人
招聘应聘

招聘应聘

为Gopher服务的招聘应聘平台

Go在数据科学领域的文章

niugou 回复了问题 • 4 人关注 • 2 个回复 • 2695 次浏览 • 2016-10-28 21:30 • 来自相关话题

针对新手的Go在线练习网站

zhqqqy 回复了问题 • 21 人关注 • 5 个回复 • 6825 次浏览 • 2016-10-28 14:28 • 来自相关话题

Docker与Golang的巧妙结合

田浩浩 发表了文章 • 0 个评论 • 3224 次浏览 • 2016-10-27 11:48 • 来自相关话题

**译文转载:[Docker与Golang的巧妙结合](http://dockone.io/article/1712)** --- 【编者的话】这是一个展示在使用Go语言时如何让Docker更有用的提示与技巧 ...查看全部
**译文转载:[Docker与Golang的巧妙结合](http://dockone.io/article/1712)**

---

【编者的话】这是一个展示在使用Go语言时如何让Docker更有用的提示与技巧的简辑。例如,如何使用不同版本的Go工具链来编译Go代码,如何交叉编译到不同的平台(并且测试结果!),或者如何制作真正小的容器镜像。

下面的文章假定你已经安装了Docker。不必是最新版本(这篇文章不会使用Docker任何花哨的功能)。

## 没有go的Go
*...意思是:“不用安装`go`就能使用Go”*

如果你写Go代码,或者你对Go语言有一点点兴趣,你肯定要安装了Go编译器和Go工具链,所以你可能想知道:“重点是什么?”;但有些情况下,你想不安装`Go`就来编译Go。

* 机器上依旧有老版本Go 1.2(你不能或不想更新),不得不使用这个代码库,需要一个高版本的工具链。
* 想使用Go1.5的交叉编译功能(例如,确保能从一个Linux系统创建操作系统X的二进制文件)。
* 想拥有多版本的Go,但不想完全弄乱系统。
* 想100%确定项目和它所有的依赖,下载,建立和运行在一个纯净的系统上。

如果遇到上述情况,找Docker来解决!

### 在容器里编译一个程序

当你安装了Go,你可以执行`go get -v github.com/user/repo`来下载,创建和安装一个库。(`-v`只是信息显示,如果你喜欢工具链快速和静默地运行,可以将它移除!)

你也可以执行`go get github.com/user/repo/...`来下载,创建和安装那个repo(包括库和二进制文件)里面所有的东西。

我们可以在一个容器里面这样做!

试试这个:
```
docker run golang go get -v github.com/golang/example/hello/...
```

这将拉取golang镜像(除非你已经有了,那它会马上启动),并且创建一个基于它的容器。在那个容器里,go会下载一个“hello world”的例子,创建它,安装它。但它会把它安装到这个容器里……我们现在怎么运行那个程序呢?

###在容器里运行程序
一个办法是提交我们刚刚创建的容器,即,打包它到一个新的镜像:
```
docker commit $(docker ps -lq) awesomeness
```

注意:`docker ps –lq`输出最后一个执行的容器的ID(只有ID!)。如果你是机器的唯一用户,并且你从上一个命令开始没有创建另一个容器,那这个容器就是你刚刚创建的“hello world”的例子。

现在,可以用刚刚构建的镜像创建容器来运行程序:
```
docker run awesomeness hello
```

输出会是`Hello, Go examples!`。

### 闪光点
当用`docker commit`构建镜像时,可以用`--change`标识指定任意[Dockerfile](https://docs.docker.com/engine/reference/builder/)命令。例如,可以使用一个`CMD`或者`ENTRYPOINT`命令以便`docker run awesomeness`自动执行hello。

###在一次性容器上运行
如果不想创建额外的镜像只想运行这个Go程序呢?

使用:
```
docker run --rm golang sh -c \
"go get github.com/golang/example/hello/... && exec hello"
```

等等,那些花哨的东西是什么?

* `--rm` 告诉Docker CLI一旦容器退出,就自动发起一个`docker rm`命令。那样,不会留下任何东西。
* 使用shell逻辑运算符`&&`把创建步骤(`go get`)和执行步骤(`exec hello`)联接在一起。如果不喜欢shell,`&&`意思是“与”。它允许第一部分`go get...`,并且如果(而且仅仅是如果!)那部分运行成功,它将执行第二部分(`exec hello`)。如果你想知道为什么这样:它像一个懒惰的`and`计算器,只有当左边的值是`true`才计算右边的。
* 传递命令到`sh –c`,因为如果是简单的做`docker run golang "go get ... && hello"`,Docker将试着执行名为`go SPACE get SPACE etc`的程序。并且那不会起作用。因此,我们启动一个shell,并让shell执行命令序列。
* 使用`exec hello`而不是`hello`:这将使用hello程序替代当前的进程(我们刚才启动的shell)。这确保`hello`在容器里是PID 1。而不是shell的是PID 1而`hello`作为一个子进程。这对这个微小的例子毫无用处,但是当运行更有用的程序,这将允许它们正确地接收外部信号,因为外部信号是发送给容器里的PID 1。你可能会想,什么信号啊?好的例子是`docker stop`,发送`SIGTERM`给容器的PID 1。

###使用不同版本的Go
当使用`golang`镜像,Docker扩展为`golang:latest,`将(像你所猜的)映射到Docker Hub上的最新可用版本。

如果想用一个特定的Go版本,很容易:在镜像名字后面用那个版本做标签指定它。

例如,想用Go 1.5,修改上面的例子,用`golang:1.5`替换`golang`:
```
docker run --rm golang:1.5 sh -c \
"go get github.com/golang/example/hello/... && exec hello"
```

你能在Docker Hub的[Golang镜像页面](https://hub.docker.com/r/library/golang/tags/)上看到所有可用的版本(和变量)。

###在系统上安装
好了,如果想在系统上运行编译好的程序,而不是一个容器呢?我们将复制这个编译了的二进制文件到容器外面。注意,仅当容器架构和主机架构匹配的时候,才会起作用;换言之,如果在Linux上运行Docker。(我排除的可能是运行Windows容器的人!)

最容易在容器外获得二进制文件的方法是映射`$GOPATH/bin`目录到一个本地目录,在`golang`容器里,`$GOPATH`是`/go.`所以我们可以如下操作:
```
docker run -v /tmp/bin:/go/bin \
golang go get github.com/golang/example/hello/...
/tmp/bin/hello
```

如果在Linux上,将看到`Hello, Go examples!`消息。但如果是,例如在Mac上,可能会看到:
```
-bash:
/tmp/test/hello: cannot execute binary file
```

我们又能做什么呢?

###交叉编译
Go 1.5具备[优秀的开箱即用交叉编译能力](http://dave.cheney.net/2015/08/22/cross-compilation-with-go-1-5),所以如果你的容器操作系统和/或架构和你的系统不匹配,根本不是问题!

开启交叉编译,需要设置`GOOS`和/或`GOARCH`。

例如,假设在64位的Mac上:
```
docker run -e GOOS=darwin -e GOARCH=amd64 -v /tmp/crosstest:/go/bin \
golang go get github.com/golang/example/hello/...
```

交叉编译的输出不是直接在`$GOPATH/bin`,而是在`$GOPATH/bin/$GOOS_$GOARCH.`。换言之,想运行程序,得执行`/tmp/crosstest/darwin_amd64/hello.`。

###直接安装到$PATH
如果在Linux上,甚至可以直接安装到系统bin目录:
```
docker run -v /usr/local/bin:/go/bin \
golang get github.com/golang/example/hello/...
```

然而,在Mac上,尝试用`/usr`作为一个卷将不能挂载Mac的文件系统到容器。会挂载Moby VM(小Linux VM藏在工具栏Docker图标的后面)的`/usr`目录。(译注:目前Docker for Mac版本可以自定义设置挂载路径)

但可以使用`/tmp`或者在你的home目录下的什么其它目录,然后从这里复制。
## 创建依赖镜像
我们用这种技术产生的Go二进制文件是静态链接的。这意味着所有需要运行的代码包括所有依赖都被嵌入了。动态链接的程序与之相反,不包含一些基本的库(像“libc”)并且使用系统范围的复制,是在运行时确定的。

这意味着可以在容器里放弃Go编译好的程序,没有别的,并且它会运行。

我们试试!

###scratch镜像
Docker生态系统有一个特殊的镜像:`scratch.`这是一个空镜像。它不需要被创建或者下载,因为定义的就是空的。

给新的Go依赖镜像创建一个新的空目录。

在这个新目录,创建下面的Dockerfile:
```
FROM scratch
COPY ./hello /hello
ENTRYPOINT ["/hello"]
```

这意味着:*从scratch开始(一个空镜像),*增加`hello`文件到镜像的根目录,*定义`hello`程序为启动这个容器后默认运行的程序。

然后,产生`hello`二进制文件如下:
```
docker run -v $(pwd):/go/bin --rm \
golang go get github.com/golang/example/hello/...
```

**注意**:不需要设置`GOOS`和`GOARCH`,正因为,想要一个运行在Docker容器里的二进制文件,不是在主机上。所以不用设置这些变量!

然后,创建镜像:
```
docker build -t hello .
```

测试它:
```
docker run hello
```

(将显示“Hello, Go examples!”)

最后但不重要,检查镜像的大小:
```
docker images hello
```

如果一切做得正确,这个镜像大约2M。相当好!

###构建东西而不推送到Github
当然,如果不得不推送到GitHub,每次编译都会浪费很多时间。

想在一个代码段上工作并在容器中创建它时,可以在`golang`容器里挂载一个本地目录到`/go`。所以`$GOPATH`是持久调用:`docker run -v $HOME/go:/go golang ....`

但也可以挂载本地目录到特定的路径上,来“重载”一些包(那些在本地编辑的)。这是一个完整的例子:
```
# Adapt the two following environment variables if you are not running on a Mac
export GOOS=darwin GOARCH=amd64
mkdir go-and-docker-is-love
cd go-and-docker-is-love
git clone git://github.com/golang/example
cat example/hello/hello.go
sed -i .bak s/olleH/eyB/ example/hello/hello.go
docker run --rm \
-v $(pwd)/example:/go/src/github.com/golang/example \
-v $(pwd):/go/bin/${GOOS}_${GOARCH} \
-e GOOS -e GOARCH \
golang go get github.com/golang/example/hello/...
./hello
# Should display "Bye, Go examples!"
```

## 网络包和CGo的特殊情况
进入真实的Go代码世界前,必须承认的是:在二进制文件上有一点点偏差。如果在使用CGo,或如果在使用`net`包,Go链接器将生成一个动态库。这种情况下,`net`包(里面确实有许多有用的Go程序!),罪魁祸首是DNS解析。大多数系统都有一个花哨的,模块化的名称解析系统(像名称服务切换),它依赖于插件,技术上,是动态库。默认地,Go将尝试使用它;这样,它将产生动态库。

我们怎么解决?

###重用另一个版本的libc
一个解决方法是用一个基础镜像,有那些程序功能所必需的库。几乎任何“正规”基于GNU libc的Linux发行版都能做到。所以,例如,使用`FROM debian`或`FROM fedora`,替代`FROM scratch`。现在结果镜像会比原来大一些;但至少,大出来的这一点将和系统里其它镜像共享。

注意:这种情况不能使用Alpine,因为Alpine是使用musl库而不是GNU libc。

###使用自己的libc
另一个解决方案是像做手术般地提取需要的文件,用`COPY`替换容器里的。结果容器会小。然而,这个提取过程困难又繁琐,太多更深的细节要处理。

如果想自己看,看看前面提到的`ldd`和名称服务切换插件。

###用netgo生成静态二进制文件
我们也可以指示Go不用系统的libc,用本地DNS解析代替Go的`netgo`。

要使用它,只需在`go get`选项加入`-tags netgo -installsuffix netgo`。

* `-tags netgo`指示工具链使用`netgo`。
* `-installsuffix netgo`确保结果库(任何)被一个不同的,非默认的目录所替代。如果做多重`go get`(或`go build`)调用,这将避免代码创建和用不用netgo之间的冲突。如果像目前我们讲到的这样,在容器里创建,是完全没有必要的。因为这个容器里面永远没有其他Go代码要编译。但它是个好主意,习惯它,或至少知道这个标识存在。

## SSL证书的特殊情况
还有一件事,你会担心,你的代码必须验证SSL证书;例如,通过HTTPS联接外部API。这种情况,需要将根证书也放入容器里,因为Go不会捆绑它们到二进制文件里。

###安装SSL证书
再次,有很多可用的选择,但最简单的是使用一个已经存在的发布里面的包。

Alpine是一个好的选择,因为它非常小。下面的`Dockerfile`将给你一个小的基础镜像,但捆绑了一个过期的跟证书:
```
FROM alpine:3.4
RUN apk add --no-cache ca-certificates apache2-utils
```

来看看吧,结果镜像只有6MB!

注意:`--no-cache`选项告诉`apk`(Alpine包管理器)从Alpine的镜像发布上获取可用包的列表,不保存在磁盘上。你可能会看到Dockerfiles做这样的事`apt-get update && apt-get install ... && rm -rf /var/cache/apt/*`;这实现了(即在最终镜像中不保留包缓存)与一个单一标志相当的东西。

一个附加的回报:把你的应用程序放入基于Alpine镜像的容器,让你获得了一堆有用的工具。如果需要,现在你可以吧shell放入容器并在它运行时做点什么。

## 打包
我们看到Docker如何帮助我们在干净独立的环境里编译Go代码;如何使用不同版本的Go工具链;以及如何在不同的操作系统和平台之间交叉编译。

我们还看到Go如何帮我们给Docker创建小的,容器依赖镜像,并且描述了一些静态库和网络依赖相关的微妙联系(没别的意思)。

除了Go是真的适合Docker项目这个事实,我们希望展示给你的是,Go和Docker如何相互借鉴并且一起工作得很好!

###致谢
这最初是在2016年GopherCon骇客日提出的。

我要感谢所有的校对材料、提出建议和意见让它更好的人,包括但不局限于:

- [Aaron Lehmann](https://github.com/aaronlehmann)
- [Stephen Day](https://twitter.com/stevvooe)
- [AJ Bowen](https://twitter.com/s0ulshake)

所有的错误和拼写错误都是我自己的;所有的好东西都是他们的!

**原文链接:[Docker + Golang = <3](https://blog.docker.com/2016/09/docker-golang/)(翻译:[陈晏娥](http://dockone.io/people/cyeaaa) 审校:[田浩浩](http://dockone.io/people/llitfkitfk))**

GoCN第二期《老司机带你看Go风景》——数据库达人陈非

hmly 回复了问题 • 13 人关注 • 13 个回复 • 20712 次浏览 • 2016-10-26 18:16 • 来自相关话题

go实现抓妹子图片

wwdyy 发表了文章 • 4 个评论 • 1584 次浏览 • 2016-10-26 14:09 • 来自相关话题

转自csdn,作者:vspeter -------------------- ```go import ( "bytes" "fmt" "io/ioutil" "net/htt ...查看全部
转自csdn,作者:vspeter
--------------------
```go
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"os"
"regexp"
"strconv"
)

const (
PATH string = "~/meizi" //文件存储路径
STARTURL string = "http://www.mzitu.com/model" //妹子图模块列表页url
CONCURRENCY int = 3 //并发下载数
)

var (
c1 chan string //通道:负责STARTURL,以后可以做成从命令参数里读取哦
c2 chan string //通道: 负责传输所有的模块url
c3 chan []string //通道:负责传输imgUrl
c4 chan int //通道: 负责传输每张图片的下载完成状态
c5 chan int //通道:负责传输当前下载数
)

func init() {
c1 = make(chan string, 1)
c2 = make(chan string, 100)
c3 = make(chan []string, 1000)
c4 = make(chan int, 3)
c5 = make(chan int, 10)
go CgetList()
go Cdownload()
}
func main() {
c1 <- STARTURL
go CgetModel()
num := 0
for count := range c5 {
num = num + count
fmt.Println("已下载:", num)
}
}

//调度器, 拉取所有模块
func CgetModel() {
modelPage := getPage(<-c1)
for i := 1; i <= modelPage; i++ {
modelUrl := STARTURL + "/page/" + strconv.Itoa(i)
c2 <- modelUrl
}
}

//调度器拉取所有图片url,这里其实还可以多分一层
func CgetList() {
k := 0
tmp := make([]string, 3)
for modelUrl := range c2 {
imgLists := getList(modelUrl)
for _, imgList := range imgLists {
imgPage := getPage(imgList)
for j := 1; j <= imgPage; j++ {
imgUrl := imgList + "/" + strconv.Itoa(j)
if k < CONCURRENCY {
tmp[k] = imgUrl
k++
} else {
c3 <- tmp
k = 0
}
}
}
if k != 0 {
c3 <- tmp
k = 0
}
}

}

//调度器, 下载图片
func Cdownload() {
for imgUrls := range c3 {
if len(imgUrls) > 0 {
for _, imgUrl := range imgUrls {
go func() {
download(imgUrl)
c4 <- 1
}()
}
num := 0
for k := range c4 {
num = num + k
if num == len(imgUrls) {
c5 <- num
break
}
}
}
}
}

//图片列表
func getList(url string) (l []string) {
reg, _ := regexp.Compile(`

.*?

`)
_, html, _ := getHtml(url)
lists := reg.FindAllStringSubmatch(html, 1000)
for _, list := range lists {
l = append(l, list[1])
}
return
}

//下载html
func getHtml(url string) (error, string, error) {
response, err := http.Get(url)
defer response.Body.Close()
html, err1 := ioutil.ReadAll(response.Body)
return err, string(html), err1
}

//获取最大分页
func getPage(url string) (page int) {
_, html, _ := getHtml(url)
reg, _ := regexp.Compile(`(\d*)`)
s := reg.FindAllStringSubmatch(html, 200)
if len(s) < 2 {
fmt.Println("获取失败")
os.Exit(-1)
}
page, _ = strconv.Atoi(s[len(s)-1][1])
return

}

//下载图片
func download(url string) {
reg, _ := regexp.Compile(`

(.*?)

`)
reg1, _ := regexp.Compile(`http:\/\/pic\.dofay\.com/(.*)`)
_, html, _ := getHtml(url)
iterms := reg.FindAllStringSubmatch(html, 100)
for _, iterm := range iterms {
imgUrl := iterm[1]
imgPath := reg1.FindAllStringSubmatch(imgUrl, 100)
imgPaths := bytes.Split([]byte(imgPath[0][1]), []byte("/"))
path := PATH + "/" // + iterm[2]
imgResponse, _ := http.Get(imgUrl)
defer imgResponse.Body.Close()
imgByte, _ := ioutil.ReadAll(imgResponse.Body)
pInfo, pErr := os.Stat(path)
if pErr != nil || pInfo.IsDir() == false {
errDir := os.Mkdir(path, os.ModePerm)
if errDir != nil {
fmt.Println(errDir)
os.Exit(-1)
}
}
fn := path + "/" + string(imgPaths[len(imgPaths)-1])
_, fErr := os.Stat(fn)
var fh *os.File
if fErr != nil {
fh, _ = os.Create(fn)
} else {
fh, _ = os.Open(fn)
}
defer fh.Close()
fh.Write(imgByte)
}
}
```

Go 语言多版本安装及管理利器 - GVM

bingohuang 发表了文章 • 7 个评论 • 7010 次浏览 • 2016-10-25 17:58 • 来自相关话题

Go 的环境安装和配置并不复杂,首先推荐看看官网的[安装教程](https://golang.org/doc/install),介绍的非常全面详细。 如果想看中文,并拓展这方面的知识,推荐看[《Go Web 编程》](https:// ...查看全部
Go 的环境安装和配置并不复杂,首先推荐看看官网的[安装教程](https://golang.org/doc/install),介绍的非常全面详细。

如果想看中文,并拓展这方面的知识,推荐看[《Go Web 编程》](https://www.gitbook.com/book/astaxie/build-web-application-with-golang)这边开源书籍中的第一章:[Go 环境配置](https://astaxie.gitbooks.io/build-web-application-with-golang/content/zh/01.0.html),作者 [astaxie](https://github.com/astaxie) 已经讲解的非常全面直观。

但如果你有 Go 多版本的需求(比如新老版本共存),如果你想更简化 Go 环境配置(省去GOPATH、GOROOT等的配置),你还希望它支持跨平台(支持Mac和Linux),那么我特别推荐这款 Go 第三方工具:[GVM](https://github.com/moovweb/gvm)——
Go 语言多版本安装及管理利器。

GVM,类似于ruby 中的 [RVM](https://rvm.io),java 中的 [jenv](https://github.com/linux-china/jenv)(国产),可用于方便管理 Go 的版本,它有如下几个主要特性:

* 管理 Go 的多个版本,包括安装、卸载和指定使用 Go 的某个版本

* 查看官方所有可用的 Go 版本,同时可以查看本地已安装和默认使用的 Go 版本

* 管理多个 GOPATH,并可编辑 Go 的环境变量

* 可将当前目录关联到 GOPATH

* 可以查看 GOROOT 下的文件差异

尤其是前三个特性,非常实用,接下来就详细的介绍一下这款工具的安装和常用方式。

### 安装 GVM
一行脚本的事情:
```
bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)
```
需要**注意**的是,如果本地用的是 [zsh](http://www.zsh.org/ "zsh"),直接替换 [bash](https://www.gnu.org/software/bash/ "bash") 即可。

### 使用 GVM

直接输入 `gvm`,查看使用帮助
``` bash
☁ ~ gvm
Usage: gvm [command]

Description:
GVM is the Go Version Manager

Commands:
version - print the gvm version number
get - gets the latest code (for debugging)
use - select a go version to use (--default to set permanently)
diff - view changes to Go root
help - display this usage text
implode - completely remove gvm
install - install go versions
uninstall - uninstall go versions
cross - install go cross compilers
linkthis - link this directory into GOPATH
list - list installed go versions
listall - list available versions
alias - manage go version aliases
pkgset - manage go packages sets
pkgenv - edit the environment for a package set
```
帮助简单易懂,这里介绍其中其中几个常用的命令。

### 展示 Go 版本

展示当前所有可以安装的 Go 版本,最新的是 `go1.7.3`
```bash
☁ ~ gvm listall

gvm gos (available)

go1
go1.0.1
go1.0.2
go1.0.3
...
go1.7.3
```

展示本地安装好的 Go 版本,箭头表示默认使用的版本,我这里是 `go1.7.3`
```bash
☁ ~ gvm list

gvm gos (installed)

go1.4
go1.5
go1.6.2
go1.6.3
go1.7
go1.7.1
=> go1.7.3
```
对比本地没有的版本,我们就可以在线安装你需要的版本了。

### 安装指定的 Go 版本

如果是 `go 1.5-` 的版本,直接安装:
```bash
gvm install go1.4
gvm use go1.4 [--default]
```
它背后做的事情是先把源码下载下来,再用 C 做编译。

所以如果是 `go 1.5+` 的版本,因为至此 Go 实现了自举(用 Go 编译 Go),就需要用到 Go 1.4 来做编译

```bash
# -B 表示只安装二进制包
gvm install go1.4 -B
gvm use go1.4
export GOROOT_BOOTSTRAP=$GOROOT
gvm install go1.7.3
```

安装好之后,指定默认使用这个版本,加上 `--default` 即可,省去每次敲 `gvm use`
```bash
gvm use go1.7.3 --default
```

这个时候查看 go 环境变量:
```bash
☁ ~ go env
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/bingo/.gvm/pkgsets/go1.7.3/global"
GORACE=""
GOROOT="/Users/bingo/.gvm/gos/go1.7.3"
GOTOOLDIR="/Users/bingo/.gvm/gos/go1.7.3/pkg/tool/darwin_amd64"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/g_/tjrlnbjd4sl56gp0p2nk3j5h0000gn/T/go-build385345518=/tmp/go-build -gno-record-gcc-switches -fno-common"
CXX="clang++"
CGO_ENABLED="1"
```
全部帮你配置好了,看起来非常赞!

### 管理多个 GOPATH
GVM 还一个很实用的功能,可以管理多个 `GOPATH`(Go package),是通过 `gvm pkgset` 命令
```bash
☁ ~ gvm pkgset
= gvm pkgset

* http://github.com/moovweb/gvm

== DESCRIPTION:

GVM pkgset is used to manage various Go packages

== Usage

gvm pkgset Command

== Command

create - create a new package set
delete - delete a package set
use - select where gb and goinstall target and link
empty - remove all code and compiled binaries from package set
list - list installed go packages
```
说明的很详细,使用方法和 gvm 也类似,就不赘述

### 卸载
如果只是想卸载某个安装好的 Go 版本:
```
gvm uninstall go1.7.3
```
如果你想完全卸载掉 GVM 和 所有安装的 Go 版本(需谨慎):
```
gvm implode
```

### 注意和不足
* 在 Linux 下安装 GVM,需要安装相关依赖,详情见[官网说明](https://github.com/moovweb/gvm)
* GVM 官方显示没对 Windows 做支持,考虑到 Windows 不是程序员的标配吧(有同学回复用 git-windows客户端,自带bash功能,可以自行尝试安装下)。
* GVM 安装新版本之后,Go 环境变量会重新设置,为了节约磁盘空间和时间,建议把之前版本的 GOPATH 内容移动到新版本对应的 GOPATH 目录下,相关路径可以通过 `go env` 获取
* 在同一版本下,用 `gvm pkgset` 创建多个 GOPATH,可能会占用你比较大的磁盘空间
* 使用 `gvm implode` 需谨慎
* GVM 是用 `shell` 编写

Go 2.0要开新坑了啊

故城 回复了问题 • 15 人关注 • 11 个回复 • 19086 次浏览 • 2016-10-25 16:54 • 来自相关话题

10.25 每日早报

astaxie 发表了文章 • 0 个评论 • 1603 次浏览 • 2016-10-25 08:15 • 来自相关话题

10.25 每日早报 新闻: 1.Node.js包管理器npm 4.0发布,新增大量重要改进 2.奔驰分时租赁平台Car2Share随心开正式进驻SOHO中国,半小时租费9.9元 ...查看全部
10.25 每日早报

新闻:

1.Node.js包管理器npm 4.0发布,新增大量重要改进

2.奔驰分时租赁平台Car2Share随心开正式进驻SOHO中国,半小时租费9.9元

3.优步中国开始新App首发版内测,上线人工客服、与微信完成对接

4.原Uber中国高级副总裁柳甄加盟今日头条,具体任职暂未透露

5.分时租赁平台嗒嗒用车获得2000万人民币的A轮投资占股10%,旗下均为新能源汽车

6.滴滴快车拼车发布业务数据,日均订单已突破200万单,平均拼成率达70%

7.大疆发布禅思Z30远摄变焦云台相机,支持30倍光变,面向行业无人机应用市场

8.GeekPwn2016黑客嘉年华在上海开幕,神奇小子Geohot携自动驾驶系统Comma One 2参会

资源:

阿里&BCG:人工智能,未来制胜之道
http://www.bcg.com.cn/cn/newsandpublications/publications/reports/report20161013001.html

注:上述内容来源于互联网,由EGO整理

panic/recover工作原理

themoonstone 发表了文章 • 4 个评论 • 3727 次浏览 • 2016-10-24 15:09 • 来自相关话题

在Golang里面没有大家所熟悉的try-cache异常机制、而是用panic/recover代替 异常throw / catch和panic / recover是有些类似的,比如、recover的作用是捕获并返回panic提交的错误对象、这可以理 ...查看全部
在Golang里面没有大家所熟悉的try-cache异常机制、而是用panic/recover代替
异常throw / catch和panic / recover是有些类似的,比如、recover的作用是捕获并返回panic提交的错误对象、这可以理解为通过调用panic抛出一个值、该值可以通过调用recover函数进行捕获。
主要的区别是,即使当前goroutine处于panic状态,或当前goroutine中存在活动紧急情况,恢复调用仍可能无法检索这些活动紧急情况抛出的值。

For example:

```go
package main

import (
"fmt"
)

func main() {
defer func() {
defer func() {
fmt.Println("6:", recover())
}()
}()
defer func() {
func() {
fmt.Println("5:", recover())
}()
}()
func() {
defer func() {
fmt.Println("1:", recover())
}()
}()
func() {
defer fmt.Println("2:", recover())
}()
func() {
fmt.Println("3:", recover())
}()

fmt.Println("4:", recover())
panic(1)
defer func() {
fmt.Println("0:", recover()) // never go here
}()
}
```
上述程序中的7个恢复调用都没有恢复程序。 程序崩溃并打印出堆栈跟踪:

$ go run example1.go
1:
2:
3:
4:
5:
6:
panic: 1

goroutine 1 [running]:
...
显然,第0个恢复调用是不可达的。 对于其他recover,让我们先检查Go规范:
**如果满足以下任一条件,recover的返回值为nil:**
- 1.panic参数是nil
- 2.当前goroutine没有产生panic
- 3.recover不是由延迟函数直接调用。

让我们忽略第一个条件。 第二个条件覆盖第一/第二/第三和第四recover调用。 第三个覆盖第5个recover调用。 然而,三个条件中没有一个覆盖第六个recover调用。
怎样才能让recover调用起作用?如下 :

```go
import("fmt")
func main(){
defer func(){
fmt.Println(recover())// 1
}()
panic(1)
}
```
现在,panic值被recover调用捕获,并且程序不会崩溃。
那么,使recover调用生效的主要规则是什么?
首先,让我们学习一些概念和说明。
## 概念:延迟函数调用概念:延迟函数调用
当函数被延迟调用时,或者函数的调用使用defer关键字作为前缀,则调用被称为延迟调用。
```go
package main
func main(){
defer func(){// deferred function calling
func(){// not a deferred function calling
defer recover()// deferred function calling
}()
}()
func(){
// not a deferred function calling
defer func(){
/// deferred function calling
}()
}()
}
```
## 概念:函数调用级别和Goroutine执行级别

函数调用级别是指函数调用的深度,与主函数或者goroutine的入口函数相关。
```go
package main

funcmain(){
// level 0
go func(){
// level 0
func(){
// level 1
}()
func(){
// level 1
func(){
// level 2
}()
}()
}()
func(){
// level 1
func(){
// level 2
go func(){
// level 0
}()
}()
go func(){
// level 0
}()
}()
}
```
goroutine当前执行点的调用级别称为goroutine的执行级别。
## 说明:panic只能向上传播
是的,panic只能向上传播,沿着函数调用堆栈反向。panic从不通过深入到函数调用中传播。
```go
package main

import"fmt"
func main(){// calling level 0
defer func(){// calling level 1
fmt.Println("Now, the panic is still in calling level 0")
func(){// calling level 2
fmt.Println("Now, the panic is still in calling level 0")
func(){// calling level 3
fmt.Println("Now, the panic is still in calling level 0")
}()
}()
}()
defer fmt.Println("Now, the panic is in calling level 0")
func(){
// calling level 1
defer fmt.Println("Now, the panic is in calling level 1")
func(){// calling level 2
defer fmt.Println("Now, the panic is in calling level 2")
func(){// calling level 3
defer fmt.Println("Now, the panic is in calling level 3")
panic(1)
}()
}()
}()
}
```
The output:
Now, the panic is in calling level 3

Now, the panic is in calling level 2

Now, the panic is in calling level 1

Now, the panic is in calling level 0

Now, the panic is still in calling level 0

Now, the panic is still in calling level 0

Now, the panic is still in calling level 0

panic: 1

goroutine 1 [running]:

...
## 概念:panic级别

panic级别意味着panic传播到函数调用的哪一层级、因为panic只能向上传递、所以panic等级永远不加增加、只会减小、在goroutine中,当前panic的水平永远不会大于goroutine的执行水平。

## 说明:在同一层级上、新的panics会压制原有panics
```go
Example:
package main

import"fmt"
func main(){
defer fmt.Println("program will not crash")
defer func(){
fmt.Println(recover())// 3
}()
defer fmt.Println("now, panic 3 suppresses panic 2")
defer panic(3)
defer fmt.Println("now, panic 2 suppresses panic 1")
defer panic(2)
panic(1)
}
```
Outputs:

now, panic 2 suppresses panic 1

now, panic 3 suppresses panic 2

3

program will not crash

在以上程序中、我们最终只能看到一个panic 3、panic 3被recover捕获、因此程序不会崩溃
在一个goroutine中,在任何时候在相同的调用级别将有至多一个主动panic。 特别是,当执行点运行在goroutine的调用级别0时,在goroutine中最多只有一个活动的panic。

## 说明:多个主动panic在一个Goroutine中的共存
Example:
```go
package main

import"fmt"
func main(){// callnig level 0
defer fmt.Println("program will crash, for panic 3 is stll active")
defer func(){// calling level 1
defer func(){// calling level 2
fmt.Println(recover())// 6
}()// the level of panic 3 is 0.// the level of panic 6 is 1.
defer fmt.Println("now, there are two active panics: 3 and 6")
defer panic(6)// will suppress panic 5
defer panic(5)// will suppress panic 4
panic(4)// will not suppress panic 3, for they have differrent levels
// the level of panic 3 is 0.// the level of panic 4 is 1.
}()
defer fmt.Println("now, only panic 3 is active")
defer panic(3)// will suppress panic 2
defer panic(2)// will suppress panic 1
panic(1)
}
```
在该示例中,panic 6、两个处于active状态中的panic之一被recover捕获。 但是其他panic,panic 3,在主调用结束时仍然活动,所以程序将崩溃。
Outputs:

now, only panic 3 is active

now, there are two active

panics: 3 and 6

6

program will crash, for panic
3 is stll active

panic: 1

panic: 2

panic: 3

goroutine 1 [running]:
...
## 说明:低级的panics将会被首先捕获
Example:
```go
package main

import"fmt"
func main(){
defer func(){
defer func(){
fmt.Println("panic",recover(),"is recovered")// panic 2 is recovered
}()
defer fmt.Println("panic",recover(),"is recovered")// panic 1 is recovered
defer fmt.Println("now, two active panics coexist")
panic(2)
}()
panic(1)
}
```
Outputs:

now, two active panics coexist

panic 1 is recovered

panic 2 is recovered

那么,什么是使recover调用生效的主要规则是什么?
规则很简单

在一个goroutine中,如果recover调用的调用函数是F并且F调用的级别是L,则为了使recover调用生效,F调用必须是延迟调用,并且必须存在主动panic的水平为L-1。
相对来说、这是一个比go规格更好的描述、 现在你可以回页面检查为什么第一个例子中的第6个recover调用不会生效了

原文链接:http://www.tapirgames.com/blog/golang-panic-recover-mechanism

Go 边看边练 - 《Go 学习笔记》系列

leoliu 回复了问题 • 12 人关注 • 7 个回复 • 2099 次浏览 • 2016-10-24 10:00 • 来自相关话题

10.24 每日早报

astaxie 发表了文章 • 0 个评论 • 1459 次浏览 • 2016-10-24 08:15 • 来自相关话题

10.24 每日早报 新闻: 1.AT&T以股票加现金的形式收购时代华纳,收购总额854亿美元 2.美国DNS服务提供商Dyn遭受大规模DDoS攻击,导致诸多巨头网站停止服务 ...查看全部
10.24 每日早报

新闻:

1.AT&T以股票加现金的形式收购时代华纳,收购总额854亿美元

2.美国DNS服务提供商Dyn遭受大规模DDoS攻击,导致诸多巨头网站停止服务

3.IBM和日本证券公司SBI合作开发区块链债券交易系统

4.知识产权电商平台知呱呱宣布获得清华启迪战略投资,知识产权服务平台3.0上线

5.魅族将推出Flyme平板系统和TV 系统,以及线下用户课堂和线上直播培训等业务

6.优步与墨西哥最大网上银行Bankaool合作发行信用卡,以解决不发达地区网上交易问题

7.互联网影视公司奇树有鱼获中南文化1050万元投资占股3%

资源:

2016年中国跨境电商邮件营销市场报告
http://www.webpowerchina.com/knowledge/page.php?id=486

中国互联网汽车电商产业生态图谱2016
http://www.analysys.cn/view/report/detail.html?columnId=8&articleId=1000323

注:上述内容来源于互联网,由EGO整理

高可用架构·Learning as we Go(第5期)

itfanr 发表了文章 • 1 个评论 • 1435 次浏览 • 2016-10-22 15:04 • 来自相关话题

http://www.epubit.com.cn/book/details/4627 免费电子书
http://www.epubit.com.cn/book/details/4627

免费电子书

[转]Go 边看边练 -《Go 学习笔记》系列(一)

itfanr 发表了文章 • 2 个评论 • 1178 次浏览 • 2016-10-22 10:25 • 来自相关话题

https://hacpai.com/article/1437497122181 以下是目录: - Go 边看边练 -《Go 学习笔记》系列(一)- 变量、常量 - Go 边看边练 -《Go 学习 ...查看全部
https://hacpai.com/article/1437497122181

以下是目录:

- Go 边看边练 -《Go 学习笔记》系列(一)- 变量、常量
- Go 边看边练 -《Go 学习笔记》系列(二)- 类型、字符串
- Go 边看边练 -《Go 学习笔记》系列(三)- 指针
- Go 边看边练 -《Go 学习笔记》系列(四)- 控制流 1
- Go 边看边练 -《Go 学习笔记》系列(五)- 控制流 2
- Go 边看边练 -《Go 学习笔记》系列(六)- 函数
- Go 边看边练 -《Go 学习笔记》系列(七)- 错误处理
- Go 边看边练 -《Go 学习笔记》系列(八)- 数组、切片
- Go 边看边练 -《Go 学习笔记》系列(九)- Map、结构体
- Go 边看边练 -《Go 学习笔记》系列(十)- 方法
- Go 边看边练 -《Go 学习笔记》系列(十一)- 表达式
- Go 边看边练 -《Go 学习笔记》系列(十二)- 接口
- Go 边看边练 -《Go 学习笔记》系列(十三)- Goroutine
- Go 边看边练 -《Go 学习笔记》系列(十四)- Channel

beego log中增加request id的一种方式

edwinxie 发表了文章 • 7 个评论 • 4310 次浏览 • 2016-10-22 10:25 • 来自相关话题

有时候要在生产环境中追查问题,每个请求有一个唯一的request id对于定位问题十分有帮助。下面介绍一种非常简单的方式。 1. 继承beego.Controller,重写其Prepare方法,在其中生成request id并写入到当 ...查看全部
有时候要在生产环境中追查问题,每个请求有一个唯一的request id对于定位问题十分有帮助。下面介绍一种非常简单的方式。

1. 继承beego.Controller,重写其Prepare方法,在其中生成request id并写入到当前上下文的数据存储结构体中:
```go
requestId := uuid.NewV4().String()
this.Ctx.Input.SetData("requestId", requestId)
```
2. 其他地方使用request Id
```go
rid := this.Ctx.Input.GetData("requestId").(string)
beego.Info("profile request, request ID:", rid)
```

10.22 每日早报

astaxie 发表了文章 • 0 个评论 • 1473 次浏览 • 2016-10-22 10:13 • 来自相关话题

10.22 每日早报 新闻: 1.EMS与腾讯达成战略合作,用互联网+与社交赋能传统快递业 2.Docker借阿里云落地中国,后者获得Docker Engine商用版及Docker ...查看全部
10.22 每日早报

新闻:

1.EMS与腾讯达成战略合作,用互联网+与社交赋能传统快递业

2.Docker借阿里云落地中国,后者获得Docker Engine商用版及Docker DataCenter运营权

3.暴风正式推出语音聊天功能暴风语音Blizzard Voice,支持旗下所有游戏

4.沃尔玛战略投资新达达5千万美元,共同打造生鲜商超O2O零售模式

5.NBC环球将数字出版商BuzzFeed追加2亿美元投资,后者最新估值17亿美元

6.团贷网宣布获得3.75亿元C轮融资,品牌升级要做小型“陆金所”

7.工商总局公告有不法分子假借办理预付卡或预付消费的名义从事非法集资

资源:

从全球市值BIG5公司看未来科技发展趋势
http://www.aliresearch.com/blog/article/detail/id/21112.html

注:上述内容来源于互联网,由EGO整理