Go语言系列三

package

  • 1> 基本复用模块单元
    • 以首字母大写来表明可被包外代码访问
  • 2> 代码的package可以和所在的目录不一致
  • 3> 同一目录里的Go代码的package要保持一致

package

  • 1> 通过go get来获取远程依赖

    • go get -u 强制从网络更新远程依赖
  • 2> 注意代码在GitHub上的组织形式,以适应go get

    • 直接以代码路径开始,不要有src

    示例一

    示例二

    go get 下载的包保存在哪里呢?

    一般他会保存在这个目录:$GOPATH/src/import-path , 若你有多个GOPATH(工作区),

    则会保存在第一个工作区中。go env 查看go环境

init 方法

  • 1> 在main被执行前,所有依赖的package的init方法都会被执行
  • 2> 不同包的init函数按照包导入的依赖关系决定执行顺序
  • 3> 每个包可以有多个init函数
  • 4> 包的每个源文件也可以有多个init函数,这点比较特殊

依赖管理

Go未解决的依赖问题

  • 1> 同一环境下,不同项目使用同一包的不同版本
  • 2> 无法管理对包的特定版本的依赖

vendor路径

随着Go 1.5 release版本的发布,vendor目录被添加到除了GOPATH和GOROOT之外的依赖目录查找的解决方案

在Go1.6之前,你需要手动的设置环境变量

查找依赖包路径的解决方案如下:

  • 1> 当前包下的vendor目录
  • 2> 向上级目录查找,直到找到src下的vendor目录
  • 3> 在GOPATH下面查找依赖包
  • 4> 在GOROOT目录下查找

常用的依赖管理工具

godep https://github.com/tools/godep

glide https://github.com/Masterminds/glide

dep https://github.com/golang/dep

安装glide

  • 1> sudo apt install golang-glide
  • 2> glide init
  • 3> glide install

Thead vs Groutine

  • 1> 创建时默认的stack的大小

    • JDK5以后Java Thread stack 默认为1M
    • Groutine的Stack初始化大小为2K
  • 2> 和KSE (Kernel Space Entity)的对应关系

    • Java Thread 是1 :1
    • Groutine是M:N

    线程关系图

//错误写法,想想为什么?
func TestGroutine(t *testing.T) {
    for i := 0; i < 10; i++ {
        go func() {
            fmt.Println(i)
        }()
    }
    time.Sleep(time.Millisecond * 50)
}
/* !< output */
=== RUN   TestGroutine
10
10
10
10
10
10
10
10
10
10
--- PASS: TestGroutine (0.05s)

共享内存并发机制

Lock

Lock lock = ...;
lock.lock();
try{
    //process (thread-safe)
}catch(Exception ex){
}finally{
    lock.unlock();
}

Lock图

WaitGroup

var wg sync.WaitGroup
for i := 0; i < 5000; i++ {
    wg.Add(1)
    go func() {
        defer func() {
            wg.Done()
        }()
        ...
    }()
}
wg.Wait()

CSP并发机制

Communicating sequential processes

Actor Model

CSP vs Actor

  • 1> 和Actor的直接通讯不同,CSP模式则是通过Channel进行通讯的,更松耦合一些

  • 2> Go中channel是有容量限制并且独立于处理Groutine,而如Erlang,Actor模式中的mailbox容量是无限的

    ​ 接收进程也总是被动地处理消息

Channel

异步返回

/* !< java */
private static FutureTask<String> service() {
    FutureTask<String> task = new FutureTask<String>(()->"Dosomething");
    new Thread(task).start();
    return task;
}

FutureTask<String> ret = service();
    System.out.println("Do something else");
    System.out.println(ret.get());

多路选择和超时控制

select

/* !< 多渠道的选择*/
select {
    case ret := <-retCh1:
        t.Logf("result %s", ret)
    case ret := <-retCh2:
        t.Logf("result %s", ret)
    default:
        t.Error("No one returned")
}
/* !< 超时控制 */
select {
    case ret := <-retCh:
        t.Logf("result %s", ret)
    case <-time.After(time.Second * 1):
        t.Error("time out")
}

channel的关闭

  • 1> 向关闭的channel发送数据,会导致panic
  • 2> v, ok <- ch; ok为bool值,true表示正常接受,false表示通道关闭
  • 3> 所有的channel接收者都会在channel关闭时,立刻从阻塞等待中返回且上述ok值为false,这个广播机制常被利用,进行向多个订阅者同时发送信号, eg: 退出信号

任务的取消

Context与任务取消

关联任务的取消

Context

  • 1> 根Context:通过context.Background()创建
  • 2> 子Context: context.WithCancel(parentContext)创建
    • ctx, cancel := context.WithCancel(context.Background())
  • 3> 当前Context被取消时,基于它的子context都会被取消
  • 4> 接收取消通知<-ctx.Done()

并发任务: 仅执行一次

单例模式(懒汉模式,线程安全)

/* !< java */
public class Singleton {
    private static Singleton INSTANCE = null;
    private Singleton(){}
    public static Singleton getlntance() {
        if (ISTANCE == null) {
            synchronized (Singleton.class) {
                if (INSTANCE == null) {
                    INSTANCE = new Singleton();
                }
            }
        }
        return INSTANCE;
    }
}
var once sync.Once
var obj *SingletonObj

func GetSingletonObj() *SingletonObj {
    once.Do(func() {
        fmt.Printl("Create Singleton obj.")
        obj = &SingletonObj{}
    })
    return obj
}

猜你喜欢

转载自www.cnblogs.com/xuzhaoping/p/11602087.html
今日推荐