首页
留言
友情链接
壁纸
更多
关于
Search
1
dockerfile怎么执行shell脚本(利用tail -f /dev/null命令防止container启动后退出)
4,942 阅读
2
channel常见的异常总结
4,259 阅读
3
支付宝支付配置开发流程
1,403 阅读
4
HTTP 协议中的Content-Encoding
1,251 阅读
5
Laravel底层原理(二) —— 契约(Contracts)
939 阅读
PHP
composer
laravel
swoole
Docker
Linux
Go
随笔
mysql
nginx
Search
标签搜索
gopher
Docker
PHP
dockerfile
通道
go
defer
alipay
支付
git
phpstorm
IDEA
web安全
漏洞
socket
Royal
累计撰写
35
篇文章
累计收到
0
条评论
首页
栏目
PHP
composer
laravel
swoole
Docker
Linux
Go
随笔
mysql
nginx
页面
留言
友情链接
壁纸
关于
搜索到
7
篇与
Go
的结果
2023-06-21
线上服务怎么部署golang应用程序
编译我们的golang项目并生成可执行程序(二进制文件)go build main.go我们需要考虑将应用程序作为系统服务运行。为此,我们需要编写一个systemd服务文件。在/etc/systemd/system/目录中,使用vim或nano等编辑器创建一个新文件,文件名称为devcloud.service,当然您也可以为其取其他的名称在devcloud.service文件中,添加以下内容:[Unit] Description=devcloud After=syslog.target After=network.target [Service] # Modify these two values and uncomment them if you have # repos with lots of files and get an HTTP error 500 because # of that ### #LimitMEMLOCK=infinity LimitNOFILE=100000 LimitNPROC=100000 Type=forking # 如果要启动的命令是一个daemon进程, 这里的值设置为forking User=root Group=root # WorkingDirectory,程序的运行目录 WorkingDirectory=/home/goproject/src # ExecStart,程序的启动命令,必须为绝对路径,若WorkingDirectory有变动,ExecStart路径对应也要变动 ExecStart=/home/goproject/src/main Restart=always ExecStop=/bin/kill -9 $(pidof main) # Some distributions may not support these hardening directives. If you cannot start the service due # to an unknown option, comment out the ones not supported by your version of systemd. # ProtectSystem=full # PrivateDevices=yes # PrivateTmp=yes # NoNewPrivileges=true [Install] WantedBy=multi-user.target注释:常见的Type类型有以下这些:在Systemd配置文件中,常见的Type选项的取值有以下几种类型:simple:默认类型。当该服务以Type=simple启动时,Systemd会认为启动命令是简单的,不会进一步检查进程的状态。Systemd仅仅启动命令,并认为启动完成后服务已经就绪。forking:当服务启动时,Systemd会认为启动命令会派生(fork)出一个子进程,并认为服务在子进程就绪后才完成启动。此类型的服务会在主进程退出后仍然继续运行。oneshot:适用于只执行一次任务的服务。当服务启动时,Systemd会等待命令执行完成,然后认为服务已经完成启动。dbus:适用于通过DBus启动的服务。notify:适用于服务启动完成后向Systemd发送通知的情况。idle:适用于服务在空闲状态时启动的情况。exec:仅执行一次命令,不会认为服务在命令执行完成后就绪。以上是常见的Type选项的取值类型。根据您的需求和服务的特性,选择适合的Type选项来定义服务的启动类型。保存文件后,使用以下命令启动新的系统服务并将其添加到自动启动中:systemctl start devcloud systemctl enable devcloud执行以上命令后,您的服务应该已经在Linux服务器上成功运行并自动启动,可以使用以下命令查看服务启动状态:systemctl status devcloud重启/停止服务systemctl restart devcloud systemctl stop devcloud
2023年06月21日
204 阅读
0 评论
0 点赞
2022-04-24
【Gopher】go语言开发环境配置goproxy(三)
在开发过程中,有时会经常遇到有些包无法完成下载的情况,网址由于墙的原因可能无法访问这时候就需要配置goproxy代理。通过go env查看默认的GOPROXY代理是官方的路径需要换成国内的代理地址。配置goproxy阿里代理go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/,direct // Windows export GOPROXY=https://mirrors.aliyun.com/goproxy/,direct // macOS 或 Linux七牛云代理go env -w GOPROXY=https://goproxy.cn,direct // Windows export GOPROXY=https://goproxy.cn,direct // macOS 或 Linux 注意Go 1.13设置了默认的GOSUMDB=sum.golang.org,是用来验证包的有效性。这个网址由于墙的原因可能无法访问,所以可以使用下面命令来关闭:go env -w GOSUMDB=off // Windows export GOSUMDB=off // macOS 或 Linux 现在再用go build执行编译 就可以正常下载依赖包!回头发现 go的安装环境需要配置三个路径:GOROOT:go的安装目录GOPATH:项目工作目录GOPROXY:代理地址
2022年04月24日
819 阅读
0 评论
1 点赞
2022-04-21
【Gopher】go语言开发环境安装(一)
安装环境是一个程序员的必修课程,好多人学习编程都是从环境安装入门到放弃。下面我们看下go的开发环境是怎么安装的,以Linux操作系统为例:1. 安装包下载 打开下载地址:https://golang.google.cn/dl/选择最新的安装包 go1.18.1.linux-amd64.tar.gz 2. 上传解压安装包 cd /usr/local/ 重点讲下为什么要到local目录,我们发现很多安装包都是默认在/usr/local目录下面的,包括nginx、php、protobuf等等Linux 的软件安装目录是也是有讲究的,理解这一点,在对系统管理是有益的/usr:系统级的目录,可以理解为C:/Windows/,/usr/lib理解为C:/Windows/System32。/usr/local:用户级的程序目录,可以理解为C:/Progrem Files/。用户自己编译的软件默认会安装到这个目录下。/opt:用户级的程序目录,可以理解为D:/Software,opt有可选的意思,这里可以用于放置第三方大型软件(或游戏),当你不需要时,直接rm -rf掉即可。在硬盘容量不够时,也可将/opt单独挂载到其他磁盘上使用。源码放哪里?/usr/src:系统级的源码目录。/usr/local/src:用户级的源码目录然后我们通过rz -b命令 把我们下载的go安装包上传到服务器中最后通过 tar -zxvf go1.18.1.linux-amd64.tar.gz解压安装包3. 建立Go的工作空间 (俗称就是我们写的代码存放的地方,workspace,也就是GOPATH环境变量指向的目录)GO代码必须在工作空间内。工作空间是一个目录,其中包含三个子目录:src ---- 里面每一个子目录,就是一个包。包内是Go的源码文件pkg ---- 编译后生成的,包的目标文件bin ---- 生成的可执行文件这里,我们在/home目录下, 建立一个名为goproject的文件夹cd /home/ mkdir goproject cd goproject/ mkdir bin mkdir src mkdir pkg4. 添加PATH环境变量and设置GOPATH环境变量vi /etc/profile加入下面这三行:export GOROOT=/usr/local/go ##Golang安装目录 export PATH=$GOROOT/bin:$PATH ##Golang bin目录 export GOPATH=/home/goproject ##Golang项目目录 工作目录保存后,执行以下命令,使环境变量立即生效: source /etc/profile ##刷新环境变量5. 验证一下环境是否安装成功go version ##查看go版本6. 查看Go语言的环境信息go env可以看到 gopath和goroot的配置信息!环境搭建OK!
2022年04月21日
269 阅读
0 评论
0 点赞
2022-04-21
【Gopher】go语言中的协程、通道(二)
并发的介绍1. 进程和线程进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。一个进程可以创建和撤销多个线程;同一个进程中的多个线程之间可以并发执行。2. 并发和并行多线程程序在一个核的cpu上运行,就是并发。多线程程序在多个核的cpu上运行,就是并行。并发并行3. 协程和线程协程:独立的栈空间,共享堆空间,调度由用户自己控制,本质上有点类似于用户级线程,这些用户级线程的调度也是自己实现的。线程:一个线程上可以跑多个协程,协程是轻量级的线程。并发主要由切换时间片来实现"同时"运行,并行则是直接利用多核实现多线程的运行,go可以设置使用核数,以发挥多核计算机的能力;goroutine 奉行通过通信来共享内存,而不是共享内存来通信。4. 管道 管道是协程之间交换数据的一个类型化的消息队列。在管道上的写操作和读操作已提前实现了互斥,并不需要显示的去给管道加锁(在访问共享数据时,也不应该去用加锁的方式。这会严重降低性能。)可以创建任意类型的管道,包括空接口类型。方法是ch:=make(chan dataType)。go使用协程1. 创建协程 使用go关键字可以去创建一个协程。但是需要注意的是,创建的协程会随着main函数的结束而结束,所以假如创建携程后main函数就执行结束了,可能所有协程都得不到运行。为了解决这个问题,在学习时可以让main函数sleep一段时间再结束运行。例如:func main(){ for i:=0;i<5;i++{//创建五个并发的协程 go print(i)//创建协程 } time.Sleep(1*time.Second)//让main函数睡一秒 } func print(n int){ for i:=0;i<20;i++{//每个协程会输出20个(编号,数字0-19)的组合 fmt.Print("(",n,i,")") } fmt.Println()//这只能代表有一次换行,并不能说是输出20个数据后换行。 } /* 输出: (0 0)(0 1)(1 0)(1 1)(1 2)(2 0)(2 1)(2 2)(2 3)(2 4)(2 5)(2 6)(2 7)(2 8)(2 9)(2 10)(2 11)(2 12)(2 13)(2 14)(2 15)(2 16)(2 17)(2 18)(2 19) (0 2)(0 3)(0 4)(0 5)(0 6)(0 7)(0 8)(0 9)(0 10)(0 11)(0 12)(0 13)(0 14)(0 15)(0 16)(0 17)(0 18)(0 19) (3 0)(3 1)(3 2)(3 3)(3 4)(3 5)(3 6)(3 7)(3 8)(3 9)(3 10)(1 3)(1 4)(1 5)(1 6)(1 7)(1 8)(1 9)(1 10)(1 11)(1 12)(1 13)(1 14)(1 15)(1 16)(1 17)(1 18)(1 19) (4 0)(3 11)(3 12)(3 13)(3 14)(3 15)(3 16)(3 17)(3 18)(3 19) (4 1)(4 2)(4 3)(4 4)(4 5)(4 6)(4 7)(4 8)(4 9)(4 10)(4 11)(4 12)(4 13)(4 14)(4 15)(4 16)(4 17)(4 18)(4 19) */可以看出,协程执行的顺序和创建的顺序并不一定相同。同时,一个携程也并不是从头到尾一次性执行完毕,他可能在函数体内部任意一条语句后就转去执行别的协程。因此,创建的五个协程内的5个fmt.Println()并不是每20个输出后换行,在最极端的情况下,可能出现输出连续输出100个元素后换行5次的情况。但在实际开发中,肯定不会使用sleep的方法让协程完成运行。应该使用sync包下的WaitGroup结构体中的Add() Done() Wait()三个函数去解决问题。2. 创建通道 和切片、map一样,通道也需要使用make创建。所以通道有下面两种创建方法:var ch1 chan int//先声明 ch1=make(chan int)//再分配空间 ch2:=make(chan int)//声明时分配3. 发送和接收数据 在向通道发送和接收数据时,都要用到<-操作符,该操作符的箭头指向为数据的流向。当发送数据时,使用msg:=<-ch来将通道中的数据发送到msg中。数据一旦从通道中取出,那么通道中就不会再存在这个数据了。向通道发送msg数据的方法为 ch<-msg。例子:func main(){ ch1:=make(chan int) go print(ch1)//创建输出数据的协程,将通道作为参数传入 go send(ch1)//创建产生数据的协程 time.Sleep(1*time.Second) } func send(ch chan int){ for i:=0;i<10;i++{ ch<-i//向通道中传入1-9 } } func print(ch chan int){ for i:=0;i<10;i++{ fmt.Print(<-ch," ")//从通道中将数据取出 } } /* 输出: 0 1 2 3 4 5 6 7 8 9 */但是需要注意的是,上面创建的通道都是缓冲为0的通道。这个意思是,如果有一个协程发送数据到通道时没有被其他协程立即接收,那么这个数据将会丢失。所以做法是make通道时增加他的缓冲。如:make(chan int,1)即创建一个缓冲为1的通道。下面这个程序将会出现死锁:func main(){ ch1:=make(chan int) ch1<-999//缓冲为0,发送到ch1之后,这个数据就会丢失。 go print(ch1)//这个协程等不到数据传入,所以会发生死锁。 time.Sleep(1*time.Second) } func print(ch chan int){ fmt.Println(<-ch) } /* 报错: all goroutines are asleep - deadlock! */如果将上述程序第二行的ch1:=make(chan int)改为ch1:=make(chan int,1)那么程序就会正常执行,输出999。4. 关闭通道 go中,使用close(ch)来关闭一个通道,释放资源。但即使是对一个已关闭的通道进行接收操作,也不会报错,这时就需要用到<-ch的第二个参数了。msg,ok:=<-ch才是一个通道正确的读取方法,如果通道已经被关闭,那么ok将会是false,否则为true。例子:func main(){ ch1:=make(chan int) go print(ch1) go send(ch1) time.Sleep(1*time.Second) } func send(ch chan int){ for i:=0;i<5;i++{ ch<-i } close(ch)//传入五个数据后就关闭通道 } func print(ch chan int){ for i:=0;i<20;i++{//连续读取二十个数据 v,ok:=<-ch fmt.Print("(",v,ok,")") } } /* 输出: (0 true)(1 true)(2 true)(3 true)(4 true)(0 false)(0 false)(0 false)(0 false)(0 false)(0 false)(0 false)(0 false)(0 false)(0 false)(0 false)(0 false)(0 false)(0 false)(0 false) */可以看出只有前五个数据是正确的。5. 迭代读取通道 如果使用for-range模式读取通道,则会自动检测通道是否被关闭。例如将上述例子的print函数替换为下面,即可自动检测通道是否被关闭了:func print(ch chan int){ for i:=range ch{ fmt.Print(i," ") } } /* 输出: 0 1 2 3 4 */6. select select的结构类似于switch-case结构,只不过他的case是通道。select语句选择一个已经准备好了的通道去执行,或是一直处于阻塞状态。例子:func main(){ ch1:=make(chan string) ch2:=make(chan string) go choose(ch1,ch2) rand.Seed(time.Now().UnixNano())//设置随机种子 for i:=0;i<5;i++{ c:=rand.Intn(2)//随机执行func1或func2 if c==0{ go func1(ch1) }else{ go func2(ch2) } } time.Sleep(1*time.Second) } func func1(ch chan string){ ch<-"11111111" } func func2(ch chan string){ ch<-"22222222" } func choose(ch1,ch2 chan string){ for{ select { //哪个通道准备好了,就执行哪个通道。 case v:=<-ch1: fmt.Println(v) case v:=<-ch2: fmt.Println(v) } } } /* 输出: 22222222 11111111 22222222 11111111 22222299 */上述程序一定会输出五条记录,因为不管是哪个通道准备好了数据,都会进行输出操作。如果choose函数写成下面这种,最极端的情况下一条数据都不会输出:func choose(ch1,ch2 chan string){ for{ fmt.Println(<-ch1) fmt.Println(<-ch2) } }
2022年04月21日
234 阅读
0 评论
0 点赞
延迟调用(defer)
Golang延迟调用:defer特性:关键字 defer 用于注册延迟调用。这些调用直到 return 前才被执。因此,可以用来做资源清理。多个defer语句,按先进后出的方式执行。defer语句中的变量,在defer声明时就决定了。defer用途:关闭文件句柄锁资源释放数据库连接释放go语言 defergo 语言的defer功能强大,对于资源管理非常方便,但是如果没用好,也会有陷阱。defer 是先进后出这个很自然,后面的语句会依赖前面的资源,因此如果先前面的资源先释放了,后面的语句就没法执行了。package main import "fmt" func main() { var whatever [5]struct{} for i := range whatever { defer fmt.Println(i) } }输出结果:432 10defer 与 returnpackage main import "fmt" func foo() (i int) { i = 0 defer func() { fmt.Println(i) }() return 2 } func main() { foo() }输出结果:2解释:在有具名返回值的函数中(这里具名返回值为 i),执行 return 2 的时候实际上已经将 i 的值重新赋值为 2。所以defer closure 输出结果为 2 而不是 1。
2021年04月25日
194 阅读
0 评论
0 点赞
1
2