Golang Go语言中 map 全局变量使用问题,请各位大佬留步一观。
Golang Go语言中 map 全局变量使用问题,请各位大佬留步一观。
各位大佬大家好,还是小弟我,这次开发遇到了一个挺坑的问题
首先说一下需求,我要完成一个任务的开始停止,对,就是这么简单。
小弟首先定义了一个全局的 map 变量去存储 job 的信息
//SyncJob 任务详情
type SyncJob struct {
ID string
Ctx context.Context
Cancel context.CancelFunc
}
//Job 单个同步任务
var Job = make(map[string]interface{})
//JobWork job 列表
var JobWork = make(map[string][]map[string]interface{})
然后我定义了一个 startwork 和 stopwork,
//SyncStart 任务开始
func SyncStart(id string) (msg string, err error) {
var job SyncJob
ctx, cancel := context.WithCancel(context.Background())
go do work(id)
job.ID = id
job.Ctx = ctx
job.Cancel = cancel
Job[id] = job
JobWork["job"] = append(JobWork["job"], Job)
return "Start work success", nil
}
//SyncStop 任务结束
func SyncStop(id string) (msg string, err error) {
for _, i := range JobWork["job"] {
jobss := i[id]
op, _ := jobss.(SyncJob)
defer op.Cancel()
}
return "Stop work success", nil
}
我尝试了一下这种写法
infiapi.SyncStart("123456")
time.Sleep(time.Second * 10)
infiapi.SyncStop("123456")
这样是可以停止任务的。 但是!小弟写了一个 web server, 想在 web server 中停止它
func StartSyncwork(w http.ResponseWriter, r *http.Request) {
r.ParseForm() //解析参数,默认是不会解析的
fmt.Println(r.Form) //这些信息是输出到服务器端的打印信息
id := r.Form["uid"]
infiapi.SyncStart(string(id[0]))
}
func StopSyncWork(w http.ResponseWriter, r *http.Request) {
r.ParseForm() //解析参数,默认是不会解析的
fmt.Println(r.Form) //这些信息是输出到服务器端的打印信息
id := r.Form[“uid”]
infiapi.SyncStop(string(id[0]))
}
…
http.HandleFunc("/start", StartSyncwork) //设置访问的路由
http.HandleFunc("/stop", StopSyncWork)
这样调用开启可以,但是 stop 无法停止,是 map 作用域的问题么?这样该如何解决呢??拜谢!
更多关于Golang Go语言中 map 全局变量使用问题,请各位大佬留步一观。的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
我试下加锁,感恩老哥
首先记得加个锁… 不然会有竞争读写问题
可以用sync.Map
和作用域无关。SyncStop
为什么要用defer
呢 直接op.Cancel()
就可以了
另外你这个多层套娃看的有点晕啊。。。搞个 repo 可以帮你看下
很久没写 golang 了,defer 这样在 for 里面用,疑似有坑。
for 里面调 defer 有泄漏的可能
搞个临时 repo 或者搞个 golang playground 出来吧,这样大家好帮你调试
谢谢老哥,问题已经解决,加了锁,优化了一下代码,感恩感恩!谢谢您!
问题已经解决,加了锁,优化了一下代码,感恩感恩!谢谢您!
把 map 作为一个 channel 穿来穿去 可解忧
1 、for 里面不要 defer, 会有泄露问题
2 、任务调度器一般不这样做的。起一个调度 goroutine 作为调度器,任务队列 chan,每个任务 go 一个协程来执行,并且创建一个 stopChan 来等待 stop 事件停止任务。然后通过 chan 或者队列的方式来投递任务和监听 chan 来消费任务。接口 start 创建任务和扔进 chan 。stop 接口发送 stop 事件到对应 stopChan,达到停止任务的目的
一看就是不知道为什么会泄露
是不知道,然后呢
不用然后,既然你不想知道,那我也没有必要告知,简单提醒一句,for 中 defer 容易泄露,并不是一定会泄露,所以是建议,而不是直接从语法上禁止
这个小心心是怎么弄出来的
貌似是楼主感谢留言才会有
在Go语言中,全局变量是一种在包级别声明的变量,它可以在该包的所有文件中访问。当涉及到map
类型的全局变量时,有一些关键点需要注意:
-
初始化:全局
map
变量需要在声明时进行初始化,否则它将默认为nil
。对nil
的map
进行操作(如读写)会引发运行时错误。因此,务必在声明时使用make
函数进行初始化,例如:var myMap = make(map[string]int)
-
并发访问:全局变量在多个goroutine之间共享时,需要考虑并发访问的问题。对于
map
,由于其不是并发安全的,所以在多个goroutine同时读写时,需要使用同步机制,如sync.Mutex
或sync.RWMutex
来保护对map
的访问。 -
生命周期:全局变量的生命周期贯穿整个程序运行过程,包括初始化、运行和退出。因此,需要特别注意在程序结束时是否需要对
map
中的资源进行清理,以避免内存泄漏。 -
命名冲突:全局变量在包内全局可见,因此命名时要避免与其他变量名冲突,建议使用具有描述性的命名方式。
总之,在使用全局map
变量时,务必注意初始化、并发访问控制、生命周期管理和命名规范,以确保程序的正确性和稳定性。希望这些建议能对你有所帮助。如果还有其他问题,欢迎继续提问。