golang-unsafe.Pointer

unsafe.Pointer

含义: 类似C的void *, 在golang中用于各种指针转换的桥梁

unsafe.Pointer 与 uintptr

相同点: 两者都可以用于转换不同类型指针

区别: uintptr 可用于指针运算,unsafe.Pointer 则不可以

e.g.

package main

import(
    "fmt"
    "unsafe"
) 

type V struct {
    i int32
    j int64
}

func (this V) PutI() {
    fmt.Printf("i=%d\n", this.i)
}

func (this V) PutJ() {
    fmt.Printf("j=%d\n", this.j)
}

func main() {
    var v *V = new(V)
    var i *int32 = (*int32)(unsafe.Pointer(v))
    *i = int32(98)
    var j *int64 = (*int64)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + uint    ptr(unsafe.Sizeof(int32(1)))))       
    *j = int64(123)
    v.PutI()
    v.PutJ()     
}

输出: 
i=98
j=0

注: 此处结果并不是我们想得到的结果, j值我们理想的值是123,但实际输出是0, 这是由于内存对齐规则造成的

内存对齐规则:
参考: http://www.cppblog.com/snailcong/archive/2009/03/16/76705.html

因为内存对齐的影响, 结构体V中的i的占用8个字节,64位, 所以,要修改j的值, 指针要在i指针的基础上+8个字节的长度, 也就是 unsafe.Sizeof(int64(1))

即:
var j int64 = (int64)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + uint ptr(unsafe.Sizeof(int64(1)))))

并发编程 - 基础摘要

并发不完全等于并行

1. 当多个程序程序同时执行时,并且分别被不同的处理器进行处理时,这才是真正意义上的并行,好比,两辆车分别行驶在不同的马路上。
2. 当并发的程序分别被执行在不同的通道上,即是并行(多核有可能), 单核只能是并发
3. 当只有一个处理器时,同时执行多个程序时,在任何一个时刻点上都只有一个程序在处理运行,但由于程序任务处于不停的切换调度当中,使得程序看起来时并行处理。我们称之为并发

IPC(进程间通讯)方式

1.基于通讯的IPC方式    
    1.1 数据传递 管道(Pipe)和消息队列(Message Queue)
    1.2 共享内存 (Shared Memory)

2.基于信号的IPC方式
    2.1 唯一异步方式

3.基于同步的IPC方式
    3.1 信号灯(Semaphore)

进程的状态

1.可运行状态(TASK_RUNNING, R)
    表示当时进程将要运行或正在CPU上运行, (注意: 该进程的运行时机是不确定的,取决于进程调度器, 因为单条线路上, 任何时刻时间点内, 可能当前进程时运行状态,但调度的是另一个运行状态的进程)


2.可中断的睡眠状态(TASK_INTERRUPTIBLE, S)
    当前进程正在等待某个事件时会进入此状态,同时,该睡眠进程会被放入事件等待队列中, 当有事件发生时, 与之相关联的进程会被唤醒。 
    比如,当前进程睡眠时,会讲当前进程的pid存放入到等待队列中,同时会与可以唤醒它的事件绑定在一起, 当事件发生时,通过便利事件等待队列,会获取需要激活的pid,激活即可。


3.不可中断的睡眠状态(TASK_UNINTERRUPTIBLE, D)
    与可中断的睡眠状态类似, 唯一区别的时,当该进程处于此状态时,此进程不会对任何信号作出响应,除非它自己完成自身绑定的事件,主动更改其状态。
    比如,当前进程睡眠是为了等待IO事件的完成, 当IO事件完成后,会主动更改起状态。 在这里, 如果IO没有完成, 我们主动向改进程发送任何信号时, 它自身状态不会改变,但,可中断的可以时时改变,并不完全依赖事件回调。



4.暂停状态或跟踪状态(TASK_STOPPED或TASK_TRACED, T)
向进程发送 SIGSTOP信号就会使改进程进入暂停状态, (处于不可中断的睡眠状态不接受此改变)

向进程发送 SIGCONT信号就会使改进程转向可运行状态,     

5.僵尸状态(TASK_DEAD-EXIT_ZOMBIE, Z)
处于此状态的进程即将要结束, 但部分信息被保留,等待父进程来为它《收拾》, 默认情况


6.退出状态(TASK_DEAD-EXIT_DEAD, X)
不保留任何信息, 非默认情况, 2种可能
    1.进程消亡时,显示的向父进程发送SIGCHLD信号, 我自己处理自己了,不劳烦父亲大人了
    2.进程分离, 子进程和父进程分别独立运行。我独立了,不用管我了。

虚拟地址

虚拟地址由 用户空间和内核空间组成, 虚拟内存的最大容量与物理内存大小无关, 系统会虚拟化一块硬盘上的内存用作虚拟内存。所以说,如果用ssd,可大大提高速写速度

线程 (TID)

一个线程是某个进程中的一个控制流, 一个进程至少包含一个线程,一个进程的第一个线程会随着它的启动而闯将,这个线程被称之为主线程。

创建线程: pthread_create

终止线程: pthread_cancel

连接终止的线程: pthread_join   连接子线程,当子线程运行结束之后,返回,执行清理操作, 否则阻塞,  如果不被连接,该线程一直处于僵尸状态,不会被系统回收,连接后,变成终止状态。可回收

分离线程: phtread_detach  子线程独立处理,结束时自己清理, 非阻塞

终止线程: pthread_exit  结束自己, 

分时调度模型:

指: 让所有线程轮流获的cpu的使用权,并且平均分配每个线程占用cpu的时间片

抢占式调度模型:

指: 优先让可运行池中优先级高的线程占用CPU,如果可运行池中的线程优先级相同,就随机选择一个线程,使其占用CPU。处于运行的线程会一直运行,直到它不得不放弃CPU

正则表达式-记录

\b 单词的开头或结尾
\bhi\b

\B \b 反义

. 除换行符以外的任意字符 (单个字符)

  • 连续重复任意次 (可能是0次)
    \bhi\b.*\bLucy\b

\d 数字
0\d\d-\d\d\d\d\d\d\d\d
0\d{2}-\d{8}

\D \d反义

\s 任意空白符(空格,制表符(Tab),换行符,中文全角空格)
\S \s反义

\w 字母 数字 下划线 汉字
\ba\w*\b

\W \w反义

+ 重复任意次(不少于1次)

^ 字符串开始
$ 字符串结束

^\d{5,12}$

? 重复零次或一次

[aeiou] 匹配任意英文元音字母
[.?!] 匹配任意符号

(\d{1,3}.){3}\d{1,3} 分组()

mongo-操作集合

1.插入命令

1.1 单个插入
db.foo.insert({"bar": "baz"})

1.2 批量插入
db.foo.insert([{"_id": 0}, {"_id" : 1}, {"_id" : 2}])

2.删除命令

2.1 条件删除
db.foo.remove({"_id": 0})

2.2 全部删除
db.foo.remove({})
db.foo.drop()        //快速删除

3.查询命令

3.1 单条查询
db.foo.findOne({"_id": 2})

3.2 查询过滤字段
//只显示 username, email 字段
db.foo.find({}, {"username" : 1, "email": 1})

//剔除字段
db.foo.find({}, {"fatal_weakness": 0})

3.3 条件查询
db.user.find({"age": {"$gte": 18, "$lte": 30}})
start = new Date("01/01/2007")
db.users.find({"registered": {"$lt": start}})

4.更新命令

4.1 单条更新
db.foo.update({"_id": 2},{"_id": 9})

4.2 多条更新
db.foo.update({"name": "liupeng"},{$set:{"name": "haha"}}, false, true)

注: 全部更新 必需配合$set关键字, 最后一位必须是true

5.$inc 修改器

5.1 单条inc
db.foo.insert({"url":"www.example.com", "pageviews": 53})
db.foo.update({"url":"www.example.com"}, {$inc:{"pageviews": 1}})

注: 属性不存在时,自动创建,  默认只取得最近一条匹配记录后返回

6.$set 修改器

6.1 单条修改
db.foo.update({"url":"www.example.com"}, {$set: {"favorite book" : "Green Eggs and Ham"}})

db.foo.update({"url":"www.example.com"}, {$set: {"favorite book" : ["Cat's Cradle","Foundation Trilogy","Ender's Game"]}})

6.2 取消属性
db.foo.update({"url":"www.example.com"}, {$unset: {"favorite book" : 1}})

7.$push 修改器

7.1 添加数组元素
db.blog.posts.update({"title":"A blog post"},{"$push":{"comments": {"name":"joe","email":"joe@example.com","content":"nice post."}}})

8.$each 修改器

8.1 添加多个值
db.blog.posts.update({"title":"A blog post"},{"$push": {"hourly": {"$each": [567.776, 562.790, 559.123]}}})

9.$slice 修改器

9.1 添加指定数量的数组元素
db.blog.posts.update({"title":"A blog post"},{"$push": {"hourly": {"$each": [00,11,22,33,44,55,66,77,88,99],"$slice": -10}}})

注: 超过10个数组时,前面的元素会舍去,保留最后的10个元素,类似队列

10.$sort 修改器

10.1 添加元素排序后保留
db.blog.posts.update({"title":"A blog post"},{"$push": {"top10": {"$each": [{"name": "Nightmare on Elm Street", "rating" : 3}, {"name": "Saw", "rating": 100}],"$slice": -10,"$sort":{"rating" : -1}}}})

注: 先添加,在排序,根据排序字段, 保留前10

11.$addToSet 修改器 (避免重复插入)

1.重复插入(会忽略)
db.users.insert({"username":"joe","emails":["joe.example.com","joe@gmail.com","joe@yahoo.com"]})
db.users.update({"username":"joe"}, {"$addToSet": {"emails":"joe@gmail.com"}})

2.插入不同
db.users.update({"username":"joe"}, {"$addToSet": {"emails":"joe@hotmail.com"}})    

3.$each 添加多个
db.users.update({"username":"joe"}, {"$addToSet": {"emails":{"$each": ["joe@php.net","joe.example.com","joe@python.org"]}}})

12.$pull 修改器 (移除特定元素)

1.$pull
db.lists.insert({"todo" : ["dishes", "laundry", "dry cleaning"]})
db.lists.update({}, {"$pull" : {"todo" : "laundry"}})

13.指定位置的数据修改器

1. 使用数组下标
db.blog.posts.insert({"content":"内容", comments:[{"comment": "good post", "author": "John", "votes": 0},{"comment" : "i thought it was too short", "author": "Claire", "votes": 3},{"comment" : "free watches", "author" : "Alice", "votes" : -1}]})

db.blog.posts.update({"_id": ObjectId("5593716bf9af3f13adea9c0b")}, {"$inc" : {"comments.0.votes": 1}})

2.不使用下标
db.blog.posts.update({"comments.author": "John"}, {"$set" : {"comments.$.author": "Jim"}})

14.upsert更新,更新时如果没有找到文档,则已更新文档为基础,创建新的文档(原子性操作)

1.e.g.
db.users.update({"rep": 25}, {$inc : {"rep": 3}}, true)

注: 开启条件是 第三个参数

2. setOnInsert (只在创建时,设置值)
db.users.update({},{"$setOnInsert" : {"createdAt": new Date()}}, true)

15.查看更新文档的数量

1.
db.count.update({x : 1}, {$inc : {x : 1}}, true, true)
db.count.update({x : 1}, {$inc : {x : 1}}, true, true)
db.count.update({x : 1}, {$inc : {x : 1}}, true, true)
db.count.update({"x":2},{"$set":{"x": 10}}, false, true)
db.runCommand({getLastError : 1})

16.$in $or 查询

1.单键查询
db.raffle.find({"ticket_no" : {"$in" : [725, 542, 390]}})

如果ticket_no 的值是 725542390 其中一个,满足条件

2.多键查询
db.raffle.find({"$or" : [{"ticket_no" : 725}, {"winner" : true}]})

如果ticket_no 是 725, 或者 winner 是true 时, 满足条件

11 索引

11.1 单条
db.users.ensureIndex({"username" : 1})

11.2 复合索引
 db.users.ensureIndex({"age": 1, "username": 1})

golang-timer

Timer

用途: 定时器

e.g.    

方式1:

    time.AfterFunc(5*time.Second, func() {
        fmt.Println("expired")
    })

方式2:

    timer := time.NewTimer(5 * time.Second)
    <-timer.C
    fmt.Println("expired")

方式3:

    <-time.After(5 * time.Second)
    fmt.Println("expired")

golang-select

Select:

用途: 监听IO操作,当IO操作发生时,触发相应的动作, 与goroutine联合使用

e.g.

package main
import(
    "fmt"
    "time"
)

func main() {
    c := make(chan int)

    go func() {
        time.Sleep(5 * time.Second)
        c <- 10
    }()

    for {
        select {
            case <-c:
            fmt.Print("trigger from chan C")
            return
        }
    }
}

golang-sync.Mutex

Mutex
用途: 排它锁, 有锁定和未锁定状态, 当处于锁定状态时, 其它尝试进行的锁定操作都被等待,直到解锁

package main
import (
    "fmt"
    "sync"
    "time"
)

var m *sync.Mutex

func main() {
     m = new(sync.Mutex)
    go lock(1)
       time.Sleep(time.Second)
    lock(2)
    fmt.Printf("%s\n", "exit!")
}

func lock(i int) {
    println(i, "lock start")
    m.Lock()
    println(i, "lock")
    time.Sleep(10 * time.Second)
    m.Unlock()
    println(i, "unlock")
}

golang-sync WaitGroup

WaitGroup

用途: 它能够等到所有goroutine执行完成,并 阻塞 主线程的执行,直到所有goroutine执行完成

在一个任务 依赖 其它多个任务的执行结果时, 并且其它任务是各自互不依赖,各自独立,就能最大发挥并行的优势, 此时主线程是阻塞的

WaitGroup方法

1.Add: 添加或者减少等待goroutine的数量

2.Done: 同 Add(-1)

3.Wait: 执行阻塞, 直到所有WaitGroup数量变成 0 

e.g.

package main
import (
   "fmt"
   "sync"
   "time"
)

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func(n int) {
            defer wg.Add(-1)
            EchoNumber(n)
        }(i)
    }
    wg.Wait()
}

func EchoNumber(i int) {
    time.Sleep(3e9)
    fmt.Println(i)
}