<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title> &#187; golang</title>
	<atom:link href="http://www.liguosong.com/category/golang/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.liguosong.com</link>
	<description></description>
	<lastBuildDate>Tue, 08 May 2018 01:02:19 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.2</generator>
		<item>
		<title>GRABC beego框架的rabc权限管理插件</title>
		<link>http://www.liguosong.com/2017/12/11/grabc-beego%e6%a1%86%e6%9e%b6%e7%9a%84rabc%e6%9d%83%e9%99%90%e7%ae%a1%e7%90%86%e6%8f%92%e4%bb%b6/</link>
		<comments>http://www.liguosong.com/2017/12/11/grabc-beego%e6%a1%86%e6%9e%b6%e7%9a%84rabc%e6%9d%83%e9%99%90%e7%ae%a1%e7%90%86%e6%8f%92%e4%bb%b6/#comments</comments>
		<pubDate>Mon, 11 Dec 2017 02:11:40 +0000</pubDate>
		<dc:creator>lgs</dc:creator>
				<category><![CDATA[golang]]></category>

		<guid isPermaLink="false">http://www.liguosong.com/?p=658</guid>
		<description><![CDATA[最近抽时间写了一个beego框架的rabc插件。这个插件包括路由、权限、角色、用户角色绑定的功能。路由功能会自 [...]]]></description>
				<content:encoded><![CDATA[<p>最近抽时间写了一个beego框架的rabc插件。这个插件包括路由、权限、角色、用户角色绑定的功能。路由功能会自动扫描controller里面的方法，然后根据需要将路由授权给权限，权限授权给角色，角色分配给用户。grabc功能简单实用，在beego框架中安装只需要不到20行的代码，即可实现rabc的功能。</p>
<p>安装：</p>
<pre class="brush:other">go get github.com/codyi/grabc</pre>
<p>配置：</p>
<pre class="brush:other">第一步：在你项目中的数据库中导入rabc.sql，生成对应数据表

第二步：在项目中引入grabc库（可以在项目中的main.go或router.go中引入）</pre>
<p>在router.go或main.go中配置如下：</p>
<pre class="brush:other">//引入grabc库
import "github.com/codyi/grabc"
func init() {
	//将路由注册到grabc，用于反射出对应的网址
	grabc.RegisterController(&amp;controllers.SiteController{})
	grabc.RegisterController(&amp;controllers.UserController{})
	//注册用户系统模型到grabc，用于用户ID和grabc插件绑定
	//注意：注册的这个用户模型，需要实现IUserModel中的方法
	grabc.RegisterUserModel(&amp;models.User{})
	//增加忽律权限检查的页面
	grabc.AppendIgnoreRoute("site", "login")
	//403页面地址注册到grabc中，用于grabc插件禁止权限的页面跳转
	grabc.Http_403("/site/nopermission")
	//设置模板，为了让grabc更具有通用性，可以设置模板
	//目前设置模板只支持传入模板的内容
	grabc.SetLayout(libs.Grabc_layout, nil)
}</pre>
<p>添加好上面的配置之后，剩下就是在controller中增加权限判了，个人建议做一个BaseController，然后每个controller都继承这个base，然后在BaseController中的方法中增加grabc的权限检查，这样每个controller在请求之前都会先检查权限~~</p>
<pre class="brush:other">BaseController.go中Prepare方法中配置如下

//注册当前登录的用户，注意：user需要继承IUserIdentify接口
grabc.RegisterIdentify(user)

if !grabc.CheckAccess(this.controllerName, this.actionName) {
	this.redirect(this.URLFor("SiteController.NoPermission"))
}</pre>
<p>到此grabc的功能都加完了，是不是很简单~~~</p>
<p>注意：增加完权限判断之后，会发现很多页面都不能访问了，那么就在router.go或main.go中增加如下代码</p>
<pre class="brush:other">grabc.AppendIgnoreRoute("*", "*")</pre>
<p>以上grabc将会忽律所有的权限检查，这时候需要去/route/index中增加路由，然后添加权限，角色和用户分配，都配置好之后，就可以将grabc.AppendIgnoreRoute(&#8220;*&#8221;, &#8220;*&#8221;)代码删掉，然后重启项目~~权限起作用了，是不是很简单~~</p>
<p>接口说明</p>
<pre class="brush:other">IUserModel接口

//用于定义用户model
type IUserModel interface {
	//用户列表返回可用用户的id和姓名
	//参数：pageIndex 分页的页数
	//参数：pageCount 每页显示的用户数量
	//返回值：userList [用户ID]用户姓名，用户列表展示
	//返回值：totalNum 全部的用户数目，用于计算分页的数量
	//返回值：err
	UserList(pageIndex, pageCount int) (userList map[int]string, totalNum int, err error)
	//根据用户ID获取用户姓名
	FindNameById(id int) string 
}
IUserIdentify接口

type IUserIdentify interface {
	GetId() int //返回当前登录用户的ID
}</pre>
<p>更过详细文档请访问：https://github.com/codyi/grabc</p>
]]></content:encoded>
			<wfw:commentRss>http://www.liguosong.com/2017/12/11/grabc-beego%e6%a1%86%e6%9e%b6%e7%9a%84rabc%e6%9d%83%e9%99%90%e7%ae%a1%e7%90%86%e6%8f%92%e4%bb%b6/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MAC OS Sublime Text 3 Golang 配置</title>
		<link>http://www.liguosong.com/2017/11/22/mac-os-sublime-text-3-golang-%e9%85%8d%e7%bd%ae/</link>
		<comments>http://www.liguosong.com/2017/11/22/mac-os-sublime-text-3-golang-%e9%85%8d%e7%bd%ae/#comments</comments>
		<pubDate>Wed, 22 Nov 2017 07:42:22 +0000</pubDate>
		<dc:creator>lgs</dc:creator>
				<category><![CDATA[golang]]></category>

		<guid isPermaLink="false">http://www.liguosong.com/?p=625</guid>
		<description><![CDATA[在看本文的前提，Go的环境一定是安装好的~~没有安装Go环境先安装Go Sublime Text 3也要提前安 [...]]]></description>
				<content:encoded><![CDATA[<p>在看本文的前提，Go的环境一定是安装好的~~没有安装Go环境先安装Go</p>
<p>Sublime Text 3也要提前安装好，可以去Sublime Text3官网下载~~官网地址：https://www.sublimetext.com/</p>
<p>打开Sublime Text 3同时输入</p>
<pre class="brush:bash"> Ctrl + `</pre>
<p>这时候Sublime Text3将出现如下界面</p>
<p><a href="http://www.liguosong.com/wp-content/uploads/2017/11/WechatIMG45.jpeg"><img class="alignnone size-large wp-image-626" alt="WechatIMG45" src="http://www.liguosong.com/wp-content/uploads/2017/11/WechatIMG45-2024x1227.jpeg" width="625" height="378" /></a></p>
<p>在最下面的输入框将下面的命令复制进去，然后回车</p>
<pre class="brush:bash">import  urllib.request,os;pf='Package Control.sublime-package';ipp=sublime.installed_packages_path();urllib.request.install_opener(urllib.request.build_opener(urllib.request.ProxyHandler()));open(os.path.join(ipp,pf),'wb').write(urllib.request.urlopen('http://sublime.wbond.net/'+pf.replace(' ','%20')).read())</pre>
<p>安装完成后会出现如下菜单<a href="http://www.liguosong.com/wp-content/uploads/2017/11/WechatIMG46.jpeg"><img class="alignnone size-full wp-image-627" alt="WechatIMG46" src="http://www.liguosong.com/wp-content/uploads/2017/11/WechatIMG46.jpeg" width="1144" height="738" /></a></p>
<p>安装完成之后，就需要安装Sublime的插件了，Ctrl + Commd + p 打开Pack Controll 然后输入pcip（即“Package Control: Install Package”的缩写）回车<a href="http://www.liguosong.com/wp-content/uploads/2017/11/WechatIMG47.jpeg"><img class="alignnone size-large wp-image-629" alt="WechatIMG47" src="http://www.liguosong.com/wp-content/uploads/2017/11/WechatIMG47-2024x982.jpeg" width="625" height="303" /></a></p>
<p>过一会将出现如下截图</p>
<p><a href="http://www.liguosong.com/wp-content/uploads/2017/11/WechatIMG48.jpeg"><img class="alignnone size-full wp-image-630" alt="WechatIMG48" src="http://www.liguosong.com/wp-content/uploads/2017/11/WechatIMG48.jpeg" width="1760" height="1086" /></a></p>
<p>这时候在输入框中输入：GoSublime将在下面列表中出现选项（注意：如果已经安装过，将不再显示），然后选中GoSublime回车，注意看Sublime Text3左下角，左下角将显示安装的进度。PS：同理继续安装：SidebarEnhancements和Go Build</p>
<p>安装GoCode，在shell中执行下面命令</p>
<pre class="brush:bash">go get -u github.com/nsf/gocode</pre>
<p>都安装完之后，重启Sublime Text3，这时候打开go的源文件代码，看看是不是代码高亮了，而且输入也有了代码提示~~~</p>
<p>PS：在Sublime Text3中执行编译源文件，需要在系统中设置好GOBIN和GOPATH，如果按住Command+b不能运行，那么在Sublime Text3中重新配置，按照下面的截图打开配置文件</p>
<p><a href="http://www.liguosong.com/wp-content/uploads/2017/11/WechatIMG49.jpeg"><img class="alignnone size-full wp-image-631" alt="WechatIMG49" src="http://www.liguosong.com/wp-content/uploads/2017/11/WechatIMG49.jpeg" width="1552" height="708" /></a></p>
<p>&nbsp;</p>
<p>然后输入下面的配置，然后再试试Command+b~~</p>
<pre class="brush:bash">{
    "GOBIN": "你本机的GOBIN目录",
    "GOPATH": "你本机的GOPATH目录"
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.liguosong.com/2017/11/22/mac-os-sublime-text-3-golang-%e9%85%8d%e7%bd%ae/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>golang boom源码分析</title>
		<link>http://www.liguosong.com/2015/08/11/golang-boom%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90/</link>
		<comments>http://www.liguosong.com/2015/08/11/golang-boom%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90/#comments</comments>
		<pubDate>Tue, 11 Aug 2015 07:10:41 +0000</pubDate>
		<dc:creator>lgs</dc:creator>
				<category><![CDATA[golang]]></category>

		<guid isPermaLink="false">http://www.liguosong.com/?p=512</guid>
		<description><![CDATA[boom是一个类似与ab的测试工具。boom起初是Tarek Ziade用python开发的。现在rakyll [...]]]></description>
				<content:encoded><![CDATA[<p>boom是一个类似与ab的测试工具。boom起初是Tarek Ziade用python开发的。现在rakyll使用golang重写。</p>
<p>boom安装，使用很简单，详细的安装和使用可以去这个网址看。https://github.com/rakyll/boom</p>
<p>boom的程序很简单，总共代码不到1000行。程序文件有：</p>
<ul>
<li><span style="line-height: 1.714285714; font-size: 1rem;">入口文件：boom.go，这个文件主要定义了boom接受的参数，main函数，请求网址解析</span></li>
<li>boomer.go 定义了几个结构体<br />
result struct 包含了每个网址请求后的结果<br />
ReqOpts struct 包含了请求网址的一些信息，例如：url，method，header等<br />
Boomer struct 包括了boom的主要信息，例如：请求的次数，并发数，Qps等</li>
<li>run.go 总共三个方法：<br />
Run 执行boom测试<br />
worker 是每个请求的协程，这里发送请求，获取请求网址的状态，以及计算请求花费的时间<br />
run 正式执行压力测试，开启规定的协程，启动worker(注意这个方法与上面的Run不一样)</li>
</ul>
<p>总结：</p>
<ol>
<li><span style="line-height: 1.714285714; font-size: 1rem;">学到了golang匿名实例化struct，并且执行struct的方法</span></li>
<li>对flag包、WaitGroup的用法有了深刻认识</li>
</ol>
<p>ps：这个程序引用了一个pd的包，pd是在终端下的进度条。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.liguosong.com/2015/08/11/golang-boom%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>golang 影响性能的写法</title>
		<link>http://www.liguosong.com/2014/09/24/golang-%e4%bb%a3%e7%a0%81%e4%bc%98%e5%8c%96/</link>
		<comments>http://www.liguosong.com/2014/09/24/golang-%e4%bb%a3%e7%a0%81%e4%bc%98%e5%8c%96/#comments</comments>
		<pubDate>Wed, 24 Sep 2014 06:40:04 +0000</pubDate>
		<dc:creator>lgs</dc:creator>
				<category><![CDATA[golang]]></category>

		<guid isPermaLink="false">http://www.liguosong.com/?p=426</guid>
		<description><![CDATA[下面有些结论是看了达达在github上的一些测试代码以及他总结出来的经验，我挑了一些，在这里进行总结一下。个人 [...]]]></description>
				<content:encoded><![CDATA[<p>下面有些结论是看了达达在github上的一些测试代码以及他总结出来的经验，我挑了一些，在这里进行总结一下。个人认为比较耗性能，平时也经常犯错的就列出来了。</p>
<p>达达的测试github地址</p>
<pre class="brush:bash">https://github.com/codyi/go-labs</pre>
<ol>
<li><span style="line-height: 1.714285714; font-size: 1rem;"><span style="line-height: 1.714285714; font-size: 1rem;"> 对slice数据结构,如果里面存放的是结构铁，不要使用range遍历，最消耗性能。可以考虑如下写法：</span></span>
<pre class="brush:c">var a := make([]BigStruct, 1000)
for i := 0; i &lt; len(a); i++ {
    obj := a[i]
}</pre>
<p>&nbsp;</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.liguosong.com/2014/09/24/golang-%e4%bb%a3%e7%a0%81%e4%bc%98%e5%8c%96/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>golang sync Cond</title>
		<link>http://www.liguosong.com/2014/05/07/golang-sync-cond/</link>
		<comments>http://www.liguosong.com/2014/05/07/golang-sync-cond/#comments</comments>
		<pubDate>Wed, 07 May 2014 12:47:26 +0000</pubDate>
		<dc:creator>lgs</dc:creator>
				<category><![CDATA[golang]]></category>
		<category><![CDATA[golang sync Cond]]></category>

		<guid isPermaLink="false">http://www.liguosong.com/?p=283</guid>
		<description><![CDATA[Cond在Locker的基础上增加的一个消息通知的功能。但是它只能按照顺序去使一个goroutine解除阻塞。 [...]]]></description>
				<content:encoded><![CDATA[<p>Cond在Locker的基础上增加的一个消息通知的功能。但是它只能按照顺序去使一个goroutine解除阻塞。</p>
<p>Cond有三个方法：Wait，Signal，Broadcast。<br />
Wait添加一个计数，也就是添加一个阻塞的goroutine。<br />
Signal解除一个goroutine的阻塞，计数减一。<br />
Broadcast接触所有wait goroutine的阻塞。<span id="more-283"></span></p>
<p>那外部传入的Locker，是对wait，Signal，Broadcast进行保护。防止发送信号的时候，不会有新的goroutine进入wait。在wait逻辑完成前，不会有新的事件发生。</p>
<p><span style="color: #ff0000;">注意：在调用Signal，Broadcast之前，应确保目标进入Wait阻塞状态。</span></p>
<p>例子：</p>
<p>&nbsp;</p>
<pre class="brush:c">package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {
	wait := sync.WaitGroup{}
	locker := new(sync.Mutex)
	cond := sync.NewCond(locker)

	for i := 0; i &lt; 3; i++ {
		go func(i int) {
			defer wait.Done()
			wait.Add(1)
			cond.L.Lock()
			fmt.Println("Waiting start...")
			cond.Wait()
			fmt.Println("Waiting end...")
			cond.L.Unlock()

			fmt.Println("Goroutine run. Number:", i)
		}(i)
	}

	time.Sleep(2e9)
	cond.L.Lock()
	cond.Signal()
	cond.L.Unlock()

	time.Sleep(2e9)
	cond.L.Lock()
	cond.Signal()
	cond.L.Unlock()

	time.Sleep(2e9)
	cond.L.Lock()
	cond.Signal()
	cond.L.Unlock()

	wait.Wait()
}</pre>
<p>输出：</p>
<pre class="brush:c">Waiting start...
Waiting start...
Waiting start...
Waiting end...
Goroutine run. Number: 0
Waiting end...
Goroutine run. Number: 1
Waiting end...
Goroutine run. Number: 2</pre>
<p>可以看出来，每执行一次Signal就会执行一个goroutine。如果想让所有的goroutine执行，那么将所有的Signal换成一个Broadcast方法可以。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.liguosong.com/2014/05/07/golang-sync-cond/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>golang sync mutex</title>
		<link>http://www.liguosong.com/2014/05/07/golang-sync-mutex/</link>
		<comments>http://www.liguosong.com/2014/05/07/golang-sync-mutex/#comments</comments>
		<pubDate>Wed, 07 May 2014 05:43:54 +0000</pubDate>
		<dc:creator>lgs</dc:creator>
				<category><![CDATA[golang]]></category>
		<category><![CDATA[sync Mutex]]></category>

		<guid isPermaLink="false">http://www.liguosong.com/?p=281</guid>
		<description><![CDATA[golang的多线程固然好用，但是有时候需要对数据进行上锁，防止数据被其它线程更改。那么sync包下的Mute [...]]]></description>
				<content:encoded><![CDATA[<p>golang的多线程固然好用，但是有时候需要对数据进行上锁，防止数据被其它线程更改。那么sync包下的Mutex非常好用。</p>
<p>Mutex是一个互斥锁。可以作为struct的一部分，这样这个struct就会防止被多线程更改数据。<br />
<span id="more-281"></span><br />
来个例子：</p>
<pre class="brush:c">package main

import (
	"fmt"
	"sync"
	"time"
)

type User struct {
	Name   string
	Locker *sync.Mutex
}

func (u *User) SetName(wati *sync.WaitGroup, name string) {
	defer func() {
		fmt.Println("Unlock set name:", name)
		u.Locker.Unlock()
		wati.Done()
	}()

	u.Locker.Lock()
	fmt.Println("Lock set name:", name)
	time.Sleep(1 * time.Second)
	u.Name = name
}

func (u *User) GetName(wati *sync.WaitGroup) {
	defer func() {
		fmt.Println("Unlock get name:", u.Name)
		u.Locker.Unlock()
		wati.Done()
	}()

	u.Locker.Lock()
	fmt.Println("Lock get name:", u.Name)
	time.Sleep(1 * time.Second)
}

func main() {
	user := User{}
	user.Locker = new(sync.Mutex)
	wait := &amp;sync.WaitGroup{}
	names := []string{"a", "b", "c"}
	for _, name := range names {
		wait.Add(2)
		go user.SetName(wait, name)
		go user.GetName(wait)
	}

	wait.Wait()
}</pre>
<p>输出结果：</p>
<pre class="brush:c">Lock set name: a
Unlock set name: a
Lock get name: a
Unlock get name: a
Lock set name: b
Unlock set name: b
Lock get name: b
Unlock get name: b
Lock set name: c
Unlock set name: c
Lock get name: c
Unlock get name: c</pre>
<p>程序很简单，就是防止在读取姓名的时候，被其它线程更改。这个程序还有些问题，不过总得来说，就是想演示一下Mutex的用途。可以让一个struct只被一个线程操作，而其它的线程就会阻塞。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.liguosong.com/2014/05/07/golang-sync-mutex/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>golang sync WaitGroup</title>
		<link>http://www.liguosong.com/2014/05/06/golang-sync-waitgroup/</link>
		<comments>http://www.liguosong.com/2014/05/06/golang-sync-waitgroup/#comments</comments>
		<pubDate>Tue, 06 May 2014 12:00:43 +0000</pubDate>
		<dc:creator>lgs</dc:creator>
				<category><![CDATA[golang]]></category>
		<category><![CDATA[sync WaitGroup]]></category>

		<guid isPermaLink="false">http://www.liguosong.com/?p=274</guid>
		<description><![CDATA[刚才看golang的sync的包，看见一个很有用的功能。就是WaitGroup。 先说说WaitGroup的用 [...]]]></description>
				<content:encoded><![CDATA[<p>刚才看golang的sync的包，看见一个很有用的功能。就是WaitGroup。</p>
<p>先说说WaitGroup的用途：它能够一直等到所有的goroutine执行完成，并且阻塞主线程的执行，直到所有的goroutine执行完成。<span id="more-274"></span></p>
<p>WaitGroup总共有三个方法：Add(delta int),Done(),Wait()。简单的说一下这三个方法的作用。</p>
<p>Add:添加或者减少等待goroutine的数量</p>
<p>Done:相当于Add(-1)</p>
<p>Wait:执行阻塞，直到所有的WaitGroup数量变成0</p>
<p>例子：</p>
<pre class="brush:c">package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {
	var wg sync.WaitGroup

	for i := 0; i &lt; 5; i = i + 1 {
		wg.Add(1)
		go func(n int) {
			// defer wg.Done()
			defer wg.Add(-1)
			EchoNumber(n)
		}(i)
	}

	wg.Wait()
}

func EchoNumber(i int) {
	time.Sleep(3e9)
	fmt.Println(i)
}</pre>
<p>输出结果：</p>
<pre class="brush:c">0
1
2
3
4</pre>
<p>程序很简单，只是将每次循环的数量过3秒钟输出。那么，这个程序如果不用WaitGroup，那么将看不见输出结果。因为goroutine还没执行完，主线程已经执行完毕。注释的defer wg.Done()和defer wg.Add(-1)作用一样。这个很好，原来执行脚本，都是使用time.Sleep，用一个估计的时间等到子线程执行完。WaitGroup很好。虽然chanel也能实现，但是觉得如果涉及不到子线程与主线程数据同步，这个感觉不错。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.liguosong.com/2014/05/06/golang-sync-waitgroup/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>golang sync once</title>
		<link>http://www.liguosong.com/2014/05/06/golang-sync-once/</link>
		<comments>http://www.liguosong.com/2014/05/06/golang-sync-once/#comments</comments>
		<pubDate>Tue, 06 May 2014 11:25:03 +0000</pubDate>
		<dc:creator>lgs</dc:creator>
				<category><![CDATA[golang]]></category>
		<category><![CDATA[sync]]></category>

		<guid isPermaLink="false">http://www.liguosong.com/?p=270</guid>
		<description><![CDATA[golang sync包下的Once是多线程开始之前先执行，并且仅执行一次的方法。可以考虑用来做一些初始化操作 [...]]]></description>
				<content:encoded><![CDATA[<p>golang sync包下的Once是多线程开始之前先执行，并且仅执行一次的方法。可以考虑用来做一些初始化操作。<span id="more-270"></span></p>
<pre class="brush:bash">package main

import (
	"fmt"
	"sync"
	"time"
)

var counter int = 0

func main() {
	var once sync.Once
	onceBody := func() {
		time.Sleep(3e9)
		fmt.Println("Only once")
	}
	done := make(chan bool)
	for i := 0; i &lt; 10; i++ {
		j := i
		go func(int) {
			once.Do(onceBody)
			fmt.Println(j)
			done &lt;- true
		}(j)
	}
	for i := 0; i &lt; 10; i++ {
		&lt;-done
	}
}</pre>
<p>输出结果：</p>
<pre class="brush:bash">Only once
0
1
2
3
4
5
6
7
8
9</pre>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.liguosong.com/2014/05/06/golang-sync-once/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>go 服务器出现too many open files的错误</title>
		<link>http://www.liguosong.com/2014/01/15/go-%e6%9c%8d%e5%8a%a1%e5%99%a8%e5%87%ba%e7%8e%b0too-many-open-files%e7%9a%84%e9%94%99%e8%af%af/</link>
		<comments>http://www.liguosong.com/2014/01/15/go-%e6%9c%8d%e5%8a%a1%e5%99%a8%e5%87%ba%e7%8e%b0too-many-open-files%e7%9a%84%e9%94%99%e8%af%af/#comments</comments>
		<pubDate>Tue, 14 Jan 2014 23:41:19 +0000</pubDate>
		<dc:creator>lgs</dc:creator>
				<category><![CDATA[golang]]></category>
		<category><![CDATA[too many open files]]></category>

		<guid isPermaLink="false">http://www.liguosong.com/?p=241</guid>
		<description><![CDATA[最近两天服务器总是会出现too many open files的错误。真的很是头疼。在本地开发环境中，也用了压 [...]]]></description>
				<content:encoded><![CDATA[<p>最近两天服务器总是会出现too many open files的错误。真的很是头疼。在本地开发环境中，也用了压力测试，发现问题不存在。但是为什么服务器会出现这种错误，有些闹不明白。本来想用ulimit更改一下打开文件的描述符。但这样子觉得并不解决问题。好吧，那就查一下更本的原因。<span id="more-241"></span></p>
<p>服务器是亚马逊，开发语言：golang，数据库：mongo，mysql。缓存：redis。</p>
<p>测试脚本：写了一个golang的并发请求脚本。大概同时请求100.ulimit限制到50.发现错误立刻呈现。发现在程序的进程下打开了大量的socket连接。所以当时就认为是mongo的连接错误。决定mongo的连接使用单例模式。不过后来发现，这些socket是会降下去的。也就是说，连接用完了，就关闭了。但是服务器的socket连接已经明显超过了ulimit的默认限制。项目也刚刚上线，也没有这么大的用户群。所以问题肯定不是处在了mongo的连接错误上。那是redis，mysql?后经过测试，也并不是这些连接的错误。</p>
<p>整的真是很晕啊。最后想起来了，可以看一下服务器的socket的连接是哪些请求。经过查看，发现是80端口。一个网站的。。搞了一天，方向错了。。。突然想起来了，最近添加的一个小功能，需要使用外网的api。在go打开连接后，好像没有关闭请求。加上关闭请求后，问题解决。socket上去，然后会自动下来。</p>
<p>总结：以后要及时关闭这些请求连接。go与php不一样。php在执行完成后，即使你不关闭请求，在解析完成后，所以变量，都会自动释放。go是编译行语言，所以连接打开后，如果不手动关闭，会一直占用。。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.liguosong.com/2014/01/15/go-%e6%9c%8d%e5%8a%a1%e5%99%a8%e5%87%ba%e7%8e%b0too-many-open-files%e7%9a%84%e9%94%99%e8%af%af/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>golang goroutine</title>
		<link>http://www.liguosong.com/2013/09/13/golang-goroutine/</link>
		<comments>http://www.liguosong.com/2013/09/13/golang-goroutine/#comments</comments>
		<pubDate>Fri, 13 Sep 2013 15:59:53 +0000</pubDate>
		<dc:creator>lgs</dc:creator>
				<category><![CDATA[golang]]></category>

		<guid isPermaLink="false">http://www.liguosong.com/?p=189</guid>
		<description><![CDATA[golang中有一个功能，我非常喜欢，就是goroutine。这个是go里面起子线程的一个功能。这个据说一个g [...]]]></description>
				<content:encoded><![CDATA[<p>golang中有一个功能，我非常喜欢，就是goroutine。这个是go里面起子线程的一个功能。这个据说一个goroutine才几KB，这个真的很小，看起来真的很不错。不过我发现在使用的过程中，如果一个子线程崩溃了，直接导致了主线程的崩溃。看来在每一个子线程中，都需要进行recover的错误捕捉。要不然编译器完了，老板会疯掉的。。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.liguosong.com/2013/09/13/golang-goroutine/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
