V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
hanguofu
V2EX  ›  Go 编程语言

go 里面的全局变量对于不同的访问,是一样的吗 ?

  •  
  •   hanguofu · 2023-12-20 07:21:29 +08:00 · 2048 次点击
    这是一个创建于 365 天前的主题,其中的信息可能已经有所发展或是发生改变。
    本人初学 :D ,写了一个简单的 web server , 请教一个简单的问题:

    在 main.go 开头有一个全局变量 ( 例如 :var search_result := [] string ) ,用于保存用户最新的搜索结果,请问如果不同的人同时访问这个 server ,搜索不同的内容,都是保存在这个全局变量里面。那么这个全局变量对于这些不同的用户来说,是否分别存在着和这些访问向对应的不同的副本 ?
    13 条回复    2023-12-21 13:59:51 +08:00
    BeijingBaby
        1
    BeijingBaby  
       2023-12-20 07:25:18 +08:00 via iPhone   ❤️ 1
    不存在副本
    nagisaushio
        2
    nagisaushio  
       2023-12-20 07:25:19 +08:00 via Android   ❤️ 1
    都是一样的
    yaott2020
        3
    yaott2020  
       2023-12-20 07:27:55 +08:00 via Android   ❤️ 1
    不存在什么副本,但是如果存在多个同时写入可能造成冲突,建议加锁。还有,你要么写 var search_result = []string{},要么写 var search_result []string ,你上面的写法是不正确的
    qloog
        4
    qloog  
       2023-12-20 08:43:07 +08:00   ❤️ 2
    在 Go 语言中,全局变量是在程序生命周期内存在的单一实例。因此,如果你在 main.go 中声明一个全局变量 searchResult ,那么它对所有的请求都是同一个实例。

    考虑到多个用户同时访问服务器的情况,这可能导致并发访问的问题。在并发情况下,多个 goroutine ( Go 程序中的轻量级线程)可能会同时尝试读取或写入全局变量,这可能导致竞态条件和数据不一致的问题。

    为了解决这个问题,你可以考虑使用互斥锁( Mutex )或者使用 Go 语言中的通道( Channel )来确保对全局变量的访问是安全的。下面是一个简单的例子,演示如何使用互斥锁:

    ```go
    package main

    import (
    "fmt"
    "net/http"
    "sync"
    )

    var (
    searchResult []string
    mutex sync.Mutex
    )

    func handleSearch(w http.ResponseWriter, r *http.Request) {
    // 使用互斥锁确保对全局变量的访问是安全的
    mutex.Lock()
    defer mutex.Unlock()

    // 这里可以对 searchResult 进行读取或写入操作
    // ...

    // 示例:向 searchResult 添加一个搜索结果
    searchResult = append(searchResult, "Search result for "+r.URL.Query().Get("query"))

    // 返回搜索结果
    fmt.Fprintf(w, "Search result added: %s\n", searchResult)
    }

    func main() {
    http.HandleFunc("/search", handleSearch)
    http.ListenAndServe(":8080", nil)
    }
    ```

    在这个例子中,使用了 sync.Mutex 来保护对 searchResult 的并发访问。在 handleSearch 函数中,通过调用 mutex.Lock() 和 mutex.Unlock() 来确保在同一时刻只有一个 goroutine 能够访问 searchResult 。这样可以避免并发访问导致的问题。
    InDom
        5
    InDom  
       2023-12-20 09:30:28 +08:00
    @qloog #4 如果是 AI 生成的,建议注明一下。
    mangoDB
        6
    mangoDB  
       2023-12-20 10:02:28 +08:00
    @qloog 使用 AI 生成回复,小心被 ban 哦。
    qloog
        7
    qloog  
       2023-12-20 10:09:17 +08:00
    @InDom
    @mangoDB
    补充,回复参考自:ChatGPT
    CloveAndCurrant
        8
    CloveAndCurrant  
       2023-12-20 10:09:43 +08:00
    如果读大于写,可以使用读写锁,没要想#4 楼那些使用互斥锁
    jonsmith
        9
    jonsmith  
       2023-12-20 10:18:00 +08:00
    包级变量(全局变量)的生命周期和整个程序的运行周期是一致的,Go 主程序( main goroutine )不结束,会一直存在。
    每个 web 请求是从主程序 main 创建的子协程 goroutine ,所有请求读写的全局变量是同一块内存,并发写时会有竞争关系,要加锁或使用 channel 。
    chengxiao
        10
    chengxiao  
       2023-12-20 10:54:50 +08:00   ❤️ 1
    你这个简单且业务量不大的处理方法是 用 map[string][]string
    为每个用户 id 设置一个[]string
    dyllen
        11
    dyllen  
       2023-12-20 15:22:37 +08:00
    没有副本,所有的用户都是读写同一个 search_result 。
    jahanngauss414
        12
    jahanngauss414  
       364 天前 via Android
    @chengxiao 并发读写 map 又是新的坑,要加锁
    chengxiao
        13
    chengxiao  
       364 天前
    @jahanngauss414 都说了前提是初学和业务量不大, 整天拿个大炮轰蚂蚁,有意思么
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3148 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 13:03 · PVG 21:03 · LAX 05:03 · JFK 08:03
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.