Visual studio各版本激活密钥
0x01 VS2015
专业版:HMGNV-WCYXV-X7G9W-YCX63-B98R2
企业版:HM6NR-QXX7C-DFW2Y-8B82K-WTYJV
0x02 VS2017
专业版:KBJFW-NXHK6-W4WJM-CRMQB-G3CDH
企业版:NJVYC-BMHX2-G77MM-4XJMR-6Q8QF
专业版:HMGNV-WCYXV-X7G9W-YCX63-B98R2
企业版:HM6NR-QXX7C-DFW2Y-8B82K-WTYJV
专业版:KBJFW-NXHK6-W4WJM-CRMQB-G3CDH
企业版:NJVYC-BMHX2-G77MM-4XJMR-6Q8QF
多线程编程中,经常会遇到这样的一种场景:main函数中为了等待其他线程执行完,在return之前都要执行sleep以争取更多的时间给其他线程执行。例如:
package main
import (
"fmt"
"time"
)
func main(){
for i := 0; i < 100 ; i++{
go fmt.Println(i)
}
time.Sleep(time.Second)
}
主线程为了等待goroutine都运行完毕,不得不在程序的末尾使用time.Sleep()
来睡眠一段时间,等待其他线程充分运行。对于简单的代码,100个for循环可以在1秒之内运行完毕,time.Sleep()
也可以达到想要的效果。但是对于实际场景来说,大多无法预知for循环内代码运行时间的长短,因此1秒可能是不够的。所以睡眠也就达不到我们想要的效果。
那么我们可能又会想到使用管道来完成同步,因为管道本身就是用来作为数据通信使用的,用在此处也合理。于是就有了这样的代码:
unc main() {
c := make(chan bool, 100)
for i := 0; i < 100; i++ {
go func(i int) {
fmt.Println(i)
c <- true
}(i)
}
for i := 0; i < 100; i++ {
<-c
}
}
首先可以肯定的是使用管道是能达到我们的目的的,但是问题是管道用在这里真的合适吗?管道是go中用来给多个线程(协程)间通信的,使用它来仅仅作为状态同步,是不是有点大材小用了。而且,管道是基于共享内存实现的,假设我们有一万、十万甚至更多的for循环,也要申请同样数量大小的管道出来,对系统性能也会造成更多的负载。
WaitGroup(中文名叫等待组)就是用来解决这种问题的,比较适合统筹多个协程间都到达某个状态。例如,等待所有协程都执行完这个状态。在WaitGroup
对象实现中,内部有一个计数器,最初从0开始,它有三个方法:
Add()
:计数器加一Done()
:计数器减一Wait()
:等待计数器清零执行Wait
方法的函数在等待组内部计数器不为0的时候回阻塞,一旦计数器为0了,程序就会继续往下执行。
利用WaitGroup
实现上面的代码:
func main() {
wg := sync.WaitGroup{}
wg.Add(100)
for i := 0; i < 100; i++ {
go func(i int) {
fmt.Println(i)
wg.Done()
}(i)
}
wg.Wait()
}
程序刚开始首先把wg
计数设置为100,然后开启100个协程执行任务,每个协程执行完成之后把计数器减1,主线程中等待计数清零。当wg.Wait()
继续向下执行了,也就说明所有的协程都执行完了。相较于管道来说,WaitGroup
更简单,也更轻量。
使用等待组时注意不能通过Add()
给wg
设置一个负值,否则代码将会报错:
panic: sync: negative WaitGroup counter
goroutine 1 [running]:
sync.(*WaitGroup).Add(0xc000014060, 0xffffffffffffffff)
/usr/local/go/src/sync/waitgroup.go:74 +0x139
main.main()
/Users/maqian/code/go/src/awesomeProject/waitgroup/waitgroup.go:10 +0x4d
同样使用Done()
也要特别注意不要把计数器设置成负数了。
WaitGroup对象不是一个引用类型,在通过函数传值的时候需要使用地址:
// 一定要通过指针传值,不然进程会进入死锁状态
func f(i int, wg *sync.WaitGroup) {
fmt.Println(i)
wg.Done()
}
func main() {
wg := sync.WaitGroup{}
wg.Add(100)
for i := 0; i < 100; i++ {
go f(i, &wg)
}
wg.Wait()
}
package main
import "fmt"
type user interface {
say(string)
}
type man struct{}
func (p *man) say(hello string) {
fmt.Println(hello)
}
func main() {
var u user = man{}
u.say("Hello World")
}
不能通过编译,因为类型man
没有实现user
接口,实现say
方法的是*man
类型,两者不能统一。
把func (p *man) say(hello string)
改成func (p man) say(hello string)
即可。
next
主题从5升级到6后,不管怎么设置语言都是一直为英语。
后面查看主题的语言包才发现6.0的中文语言包名字已经改了,之前是zh-Hans
,现在已经做了对应的调整。
[ma@ma maqianos.coding.me]$ ls -l themes/next-v6/languages/zh-*
-rw-r--r-- 1 ma root 1849 Feb 28 15:54 themes/next-v6/languages/zh-CN.yml
-rw-r--r-- 1 ma root 1842 Feb 28 15:54 themes/next-v6/languages/zh-HK.yml
-rw-r--r-- 1 ma root 1839 Feb 28 15:54 themes/next-v6/languages/zh-TW.yml
在站点配置文件_config.yml
中修改language: zh-Hans
为language: zh-CN
即可。
使用git mv
重命名文件时出现以下错误信息:
fatal: bad source, source=go/src/handle/add.go, destination=go/src/handle/add.go
源文件go/src/handle/add.go
在本地已经被删除了,但是git
库中并没有被删除,所以重命名该文件的上级目录时产生了冲突。
通过git status
可以查看到当前文件状态是已经删除:
[ma@ma test-src]$ git status -s
D handle/add.go
D handle/add_test.go
使用git rm
命令删除对应的文件,然后再重命名。
第一次听说逃逸是在雨痕学堂,一脸懵逼的百度了半天也没找到一个明确的说法,直到昨天在论坛上看到一篇关于变量逃逸的文章才明白。
因为函数都是运行在栈上的,在栈声明临时变量分配内存,函数运行完毕再回收该段栈空间,并且每个函数的栈空间都是独立的,其他代码都是不可访问的。
但是在某些情况下,栈上的空间需要在该函数被释放后依旧能访问到,这时候就涉及到内存的逃逸了。
Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.
$ hexo new "My New Post"
More info: Writing
$ hexo server
More info: Server
$ hexo generate
More info: Generating
$ hexo deploy
More info: Deployment
家里的宽带访问github非常慢,git clone
一直维持在10k/s
,这个速度实在难以接受。
试探性的搜了一下git代理,没想到还真有。。。
# 设置代理
git config --global http.proxy ''socks5://127.0.0.1:1080''
git config --global https.proxy ''socks5://127.0.0.1:1080''
# 取消代理
git config --global --unset http.proxy
git config --global --unset https.proxy
MySQL主从复制依赖binlog,binlog中记录了数据库中的执行过的语句,主从复制时,复制的并不是整个数据库中的所有数据,而是从上次同步到现在所执行过的SQL语句。
执行主从同步时,主库会有一个Log-Dump线程和从库同步,把binlog发送给从库。从库则有一个I/O线程和SQL-Thread线程分别用于和主库同步和重放。同步过程是:
默认情况下MySQL是异步复制,即SQL语句执行完成后写入binlog就可以了,不用等待主从数据同步完成。
同步复制的意思是每次执行SQL语句要等待从库写入到relay log后才能继续往下执行,这样就避免了主库以外宕机后从库数据不一致的情况。