感悟
- 之前说过前端传来的数据不可信,要进行反复校验
- 当设计一个问题的解决方案时,一定要考虑并发,分布式的情况下,此方案还可不可行
正文
- ubuntu18.04和docker的兼容性貌似很好
- nginx的默认访问路径:/usr/share/nginx/html/index.html
- nginx:alpine 最小镜像的基础
- yum -y install nginx默认安装的是fedora版本的nginx,比较大
- 每个docker都有自己的文件结构
- alpine版本的nginx的默认主页也是在那个文件夹下
- npm run build会打包项目,打包项目之后会生成dist文件,将文件拷到服务器下就可以运行
- ssh-copy-id root@ip 下次登录就不会再要求输入密码了
- sudo apt update
- 直接yum安装的docker版本比较老,推荐自己进行安装
- golang交叉编译不同平台

- 拉dokcer的golang镜像在里面进行交叉编译(二段构建,没有环境的也可以build)


rander里面的html里写入js(axios),再用js(axios)请求api(drf)
- 真nm是个人才


- 配置安全组防火墙,9000/9000 授权对象0.0.0.0/0
- 用docker来做服务保持
- caddy http/2
- 云服务器可以直接资源变更


-
docker环境变量的方式传参数
-
docker compose的yaml格式

Go
- 问题,字线程还没有跑完主线程就已经挂掉,so需要在主线程加上time.Sleep(time.Second*1)
package main
import (
"fmt"
"time"
)
// func run(a int) {
// fmt.Println(a)
// }
func main() {
for i := 1; i < 10; i++ {
go func(a int){
fmt.Println(a)
}(i)
// time.Sleep(time.Second*1)
}
time.Sleep(time.Second*1)
}
- 竞争资源不是线程安全的
- Mutex共享内存控制并发机制
共享内存加锁的并发机制
package main
import (
"testing"
"time"
)
func TestCounter(t *testing.T) {
counter := 0
for i := 0; i < 5000; i++ {
go func() {
counter++
}()
}
time.Sleep(time.Second * 1)
t.Logf("counter =%d", counter)
}

- 要求起50000个协程,但是最终起不到50000个
func TestCounter(t *testing.T) {
var mut sync.Mutex
counter := 0
for i := 0; i < 50000; i++ {
go func() {
defer func() {
mut.Unlock()
}()
mut.Lock()
counter++
}()
}
time.Sleep(time.Second * 1)
t.Logf("counter =%d", counter)
}
- 此线程安全,在++之前上个锁
- 同理此主线程也要睡1s,否则可能结果得不到预期
- 还可以用一种更加精确专业的方法做此事
package main
import (
"sync"
"testing"
// "time"
)
// 线程不安全,不好
// func TestCounter(t *testing.T) {
// counter := 0
// for i := 0; i < 5000; i++ {
// go func() {
// counter++
// }()
// }
// time.Sleep(time.Second * 1)
// t.Logf("counter =%d", counter)
// }
func TestCounter(t *testing.T) {
var mut sync.Mutex
var wg sync.WaitGroup
counter := 0
for i := 0; i < 50000; i++ {
wg.Add(1)
go func() {
defer func() {
mut.Unlock()
}()
mut.Lock()
counter++
wg.Done()
}()
}
// time.Sleep(time.Second * 1)
wg.Wait()
t.Logf("counter =%d", counter)
}

- 时间快了1s
- 分析:add等待任务,Done告诉执行完毕的信号,wait等待会阻塞,阻塞之后才会向下执行
- effective go effective python
- RWLock(读写锁)在读多写少的场景操作中使用,可以加多把读锁,或一把写锁
- sync.Mutex:互斥锁(也是全局锁,只能加一个,被锁上了需要 释放才能加下一把锁)
- https://blog.csdn.net/fwhezfwhez/article/details/82900498
- https://blog.csdn.net/u013210620/article/details/78357995
- https://blog.csdn.net/tianlongtc/article/details/80067072
CSP并发模型(go中特有的)
-
通过channel进行协调

-
channel的两种模型,一个是阻塞,一个是队列的形式
-
bufferchannel是 不阻塞的,只是在最后欧多加了个容量
package channel_demo
import(
"fmt"
"testing"
"time"
)
func service() string {
time.Sleep(time.Millisecond * 50)
return "Done"
}
func otherTask() {
fmt.Println("working on something else")
time.Sleep(time.Millisecond * 100)
fmt.Println("Task is done")
}
func TestChannel(t *testing.T) {
fmt.Println(AsyncService())
otherTask()
}
func AsyncService() chan string{
retCh := make(chan string)
go func(){
ret := service()
fmt.Println("return result")
retCh <- ret
fmt.Println("service exited.")
}()
return retCh
}
- 非阻塞的进行操作

-
实际操作少了0.5秒
-
加上容量编程buffer channel会在管道中非阻塞

-
输出结果发生了变化,说明是非阻塞的
多路选择超时控制
- 用select实现超时控制
func TestChannel(t *testing.T) {
select {
case ret := <-AsyncService():
t.Log(ret)
case <- time.After(time.Millisecond*100):
t.Error("time out")
}
}
- 如果超时了就会抛出错误
channel的关闭和广播
- 生产者消费者模式中间通过buffer,在go中通过channel实现
- 在go中有个关闭channel的操作,给出一个信号

任务取消
- struct{}{} 空结构体
- 所有的某func(xxx) 可以看成是一个工厂方法
- close的channel是广播机制的,可以用来通道关闭的广播机制来取消协程任务
本文深入探讨了并发编程在Go语言中的应用,包括线程安全、锁机制、CSP并发模型、channel的使用及超时控制等核心概念。通过实例讲解如何避免资源竞争,实现高效并发,并介绍了生产者消费者模式的实现。
996

被折叠的 条评论
为什么被折叠?



