• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

准备深飘的第三天 Go语言学习

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

昨天晚上回家之前还有一个go聊天的聊天系统没有写完,今天接着干完,对了这些天都是看的http://www.topgoer.com/这个教程在学习,这个文档比官方文档写的都要nice,安利一下。
最后写出来的效果,

但是发消息那个消息好像显示不上去,不过和我前不久刚用websocket+netty写的一个手机app的项目有点相似,但是这个go语言的调式那些我还是不太会,因为他运行的时候是 go run server.go …就是几个go文件都一起运行了,不是很了解这样操作的话那我的日志输出在什么地方,怎么去调式他,但是关系不大,因为我看到后面马上就是框架的东西了。

并发介绍
线程和进程
1.进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个单位;
2.线程是进程的一个执行实体,是cpu调度和分派的基本单位,是比进程更小的能独立运行的单位
3.一个进程中可以创建和销毁多个线程,多个线程可以在一个进程中并发运行

并发和并行
多线程程序在一个核的cpu上运行是并发
多线程程序在多个核的cpu上运行是并行

协程和线程
协程:独立栈空间,共享堆空间,调度是用自己完成的,有点类似用户级的线程,只不过这些线程的调度也是由自己完成的
线程:一个线程可以跑多个协程,协程是轻量级的线程

Goroutine
每个实例4~5kb的栈内存占用和由于实现机制而大幅度减少的创建和销毁开销是go实现高并发的根本。

Goroutine 奉行通过共享通信来共享内存,而不是通过共享内存来共享通信。
高并发不是高并行!!!

接着来看下神奇的goroutine
在go中如果要新开启一个线程执行一个函数,只需要在函数前面加上go关键字,但是当主线程结束之后,在这个线程中开启的其他并发线程也会同时结束,主线程就是夜王,其他的就是异鬼哈哈,这个比喻很形象,但是可以加上time.sleep(time.Second),等待其他的线程。
开启多线程的时候,由于线程的资源调度是随机的,所以多线程的执行顺序也是不定的。

有个例子,

我试了一下几种情况
1.主线程注释掉time

2.其他线程注释掉time

其他线程疯狂执行
3.都注释掉

这个意思就是因为开启其他线程是需要时间的,这个时间显然比主线程执行到i2这个时间要长,如果把i2的条件加大可能可以输出 new gouroutine的信息 于是我把条件变成i==1000000,猜想正确

4.都使用time

都使用time,我试了多次运行,发现由两种结果,但是都是主线程结束了,其他的也就结束了

GPM go语言的调度系统
G goroutine
P 是存储了当前goroutine的上下文数据(堆栈地址、地址边界、函数指针)管理着一组goroutine队列,负责调度分配,合理化(时间长的先暂停,)如果自己的消费完了去全局搜索,全局完了,去其他队列抢任务
M machine 最终的goroutine都是运行在这个上面的,于内核对应

总结,go单从线程角度来讲比起其他的编程语言的优势在于os线程由os系统调度,自己的goroutine是用自己的GPM完成的调度,调度是有个M:N的调度技术调度M个goroutine到n个os线程,具体的就不太了解了。

Channel通道
1.全局定义 var chan ch1
2.ch1 := make(chan int)
3.发送 ch1 <-10
4.接受 i := <- ch1
5.close()
6.有缓存的通道定义 make(chan int ,10)
7.遍历通道中的数据
方法1:

方法2:

8.单向通道 通道作为参数传递的时候,可以定义通道的流向
chan<- int是一个只能发送的通道,可以发送但是不能接收;
<-chan int是一个只能接收的通道,可以接收但是不能发送。
9.通道异常总结

定时器
使用的时候再去查
Ticker 可以多次使用的

Select 用法和swicth相同
可以用于响应多个通道的数据情况,可以监听多个channel直到其中有一个already,如果同时出现,会随机选择一个执行
并发安全锁
在启用多个goroutine去访问共享资源的时候,会因为临界区的问题出现数据的争夺,导致结果出错。
互斥锁:在数据访问之前先锁定,确保其他线程处于等待状态,操作完再解锁,其他线程操作的时候同样进行这样的操作
读写互斥锁:用于读操作多于写操作的时候
Lock mutex rwLock RWMUTEX

Sync
WaitGroup
其内部维护着一个计数器,一共有三个方法
Add() 计数器增加 Done() 计数器-1 wait()等待计数器为0

Once
用来做数据初始话,其内部使用互斥锁维护着一个布尔值,这个布尔值记录初始化是否完成,在初始化的时候,其他线程无法操作。
用法:
loadIconsOnce.Do(loadIcons)

代替原来的写法
if icons == nil {
loadIcons()
}

Map
线程安全的map,go语言内置的map是并发不安全的,
原子操作
Go对于基本数据类型的操作提供了一种叫做原子操作的东西,相比加锁的性能消耗而言,使用原子操作的性能要优于加锁

GPM调度器的生命周期

图片是从教程上面截取的就没有再去画了。
1.创建第一个线程MO
2.创建第一个Go协程GO
3.关联MO与GO
4.调度初始化
5.创建main()中的goroutine
6.启动MO
7.M绑定P
8.判断M是否能通过P获取到G,如果不能M休眠,直至再猜被唤醒,继续跳到7
如果可以获取到,继续
9.M设置G环境
10.M执行G
11.G执行完成之后,跳到8

接着就是一个比较高深的线程上面的问题了,但是我现在感觉自己看这个花费的时间会比较多,于是我就看那个我一直想看的操作数据的了。

数据库操作

但是注意的是struct中如果的变量名,名称的首字母一定要用大写的,不然会报一个错
non-struct dest type struct with >1 columns (4)
如果数据库不是varchar类型的时候,比如是decimal接受的可以用int或者float
增删改就不写了

但是在实例中有一段这个,上面的写法会说数据库已经关闭了,我觉得应该是位置写错了,我把他移到了main函数中,试一下。
猜想正确,因为在调用的地方加上才可以。这里还有个没有搞懂就是那个init方法,我在main方法中都没有调用,但是他却自己就给执行了。反正记着之后遇到这种先就记到吧,后面应该有地方会解释的。

Redis操作


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
GO学习之路 - 安装发布时间:2022-07-10
下一篇:
(空闲)部署go到服务器时的一些问题------2020.05.09发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap