我在一个 goroutine 修改环境变量, 想在其他所有 goroutine 中生效? 可以吗?
1
xhatt 2023-10-17 13:58:16 +08:00
试一下不就知道了?很简单
|
2
chaleaochexist OP |
3
qloog 2023-10-17 14:04:24 +08:00 1
Golang 默认是单进程的,这与其他语言如 Java 、Node.js 有所不同。
原因有以下几点: 1. Goroutine 更轻量,一个进程可以同时运行成千上万个 Goroutine,所以不需要多进程。 2. Goroutine 有运行时(Runtime)调度和上下文切换,不需要进程或线程切换的开销。 3. 共享内存通信更简单快捷,不需要跨进程通信。 4. 不需要考虑锁、线程安全问题,编程模型更简单。 5. GC 更容易实现且高效。 但是 Golang 也可以通过 os.Exec 启动新进程,或者在不同端口监听启动多个进程。 结论: - Golang 默认单进程,这由语言设计决定。 - 单进程可以处理更高并发,编程模型更简单。 - 也可以手动启动多进程满足特定需求。 所以 Golang 作为一种现代编程语言,单进程多 Goroutine 是更合理的选择。但也保留了启动多进程的能力。 |
4
thinkershare 2023-10-17 14:06:25 +08:00 1
Golang? 你确认没问错? 线程 or 进程?
|
5
emSaVya 2023-10-17 14:13:49 +08:00 3
这几条回答也是够逆天了 single/multi process 什么时候跟编程语言绑定了?
|
6
dode 2023-10-17 14:22:50 +08:00
goroutine 连线程都不是独立的
|
7
standchan 2023-10-17 14:22:58 +08:00 1
这个问题,都不知道该怎么开口回答。。。。
|
9
lincanbin 2023-10-17 14:25:25 +08:00 2
一个编译型语言哪来的单进程/多进程,那不取决于你代码是单进程/多进程吗?
|
10
62742a40 2023-10-17 14:25:46 +08:00
我实在不知道这个问题是怎么产生的
|
11
Ericcccccccc 2023-10-17 14:27:05 +08:00
标题和内容完全不搭啊...
回到你的问题, 实时修改环境变量能不能生效得看这个值是啥时候读的. |
12
mightybruce 2023-10-17 14:27:24 +08:00 1
我建议赶紧转行吧。
|
13
weiwenhao 2023-10-17 14:29:18 +08:00
多开几个 goroutine, ps 看一下就知道 golang 开了几个进程啦。如果想看线程就 ps -T 看一下线程数。
|
14
kkk9 2023-10-17 14:34:21 +08:00
OP 是想问全局变量和局部变量的区别吗?
|
15
leonshaw 2023-10-17 14:37:47 +08:00 2
没见过哪个语言会偷偷开进程
|
16
fregie 2023-10-17 14:45:01 +08:00 via Android
确实,这个问题我都不知道该怎么回答了....
我觉得你是想问这个:不同 goroutine 中其中一个修改了环境变量,其他的过去到的值有的是改之后的有的是改之前的。 我觉得你是没控制好获取的时机,估计有些在修改生效前就获取了 |
17
bug123 2023-10-17 14:54:24 +08:00 6
知道的和不知道的都懵逼了
|
19
ysc3839 2023-10-17 15:01:57 +08:00 via Android 1
goroutine 是单进程多线程
|
20
4kingRAS 2023-10-17 15:16:57 +08:00
看 pid 就知道了,windows 也有 pid
|
21
dw2693734d 2023-10-17 15:18:42 +08:00
哪个语言是多进程的?
|
22
wangritian 2023-10-17 15:19:14 +08:00
你有这个疑问是不是从 php-fpm 转过来的
可以这么回答,如果你没主动开进程,那它就是单进程 |
23
smallyu 2023-10-17 15:20:34 +08:00
单进程会占用多个 CPU 吗?
|
24
emSaVya 2023-10-17 15:25:07 +08:00
@dode
没有任何编程语言阻挡你选择并发模型, 最多是有个 best practice 。 python 开发者也可以写 multi thread 的代码, 只不过 GIL 存在 multi thread 不起作用而已, 而且 GIL 不是编程语言的限制 是 runtime 的限制 换一个编译器即可。 |
25
wtfedc 2023-10-17 15:52:31 +08:00
Go (也称为 Golang) 是一种编程语言,它本身并不决定程序的多进程或单进程性质。Go 语言提供了并发编程的强大工具,例如 goroutine 和通道,以支持多线程和并发编程。这意味着你可以在 Go 中轻松地创建多个并发的执行线程,而不必自己管理底层的线程或进程。
Go 程序通常是单进程的,但这个进程可以包含多个并发的 goroutine ,这些 goroutine 可以并行执行任务。这种设计使 Go 程序在处理高并发性能方面非常出色。 虽然 Go 本身不决定程序是单进程还是多进程,但开发人员可以在 Go 中使用并发编程来构建多进程应用程序,如果需要的话。例如,你可以编写一个 Go 程序,该程序启动多个进程,每个进程运行不同的任务,并且这些进程可以通过通道进行通信。 总之,Go 语言本身不限制进程的数量,但提供了丰富的并发编程工具,使开发人员能够有效地管理多个并发执行线程。 from chatGPT |
26
moonsn 2023-10-17 15:54:06 +08:00 via iPhone
看 setenv 和 getenv 的源码就知道了,有锁。还是包级别的锁。结论:多个 goroutine 并发使用是安全的。
|
27
chaleaochexist OP @thinkershare 我当然知道是多线程了.
我的问题是是否是单进程 因为环境变量的设置默认只对当前进程有效. |
28
chaleaochexist OP @emSaVya 那我换个问法 go runtime 是单进程的吗?
|
29
importlau 2023-10-17 16:11:15 +08:00
@chaleaochexist 进程之间资源是隔离的
|
30
chaleaochexist OP @emSaVya
@dode @standchan @lincanbin @62742a40 @Ericcccccccc @mightybruce @kkk9 @leonshaw @fregie @bug123 @ysc3839 @dw2693734d @wangritian @smallyu @emSaVya @wtfedc @moonsn 好吧我换个问法, 当一个 go 程序运行的时候, 当我不主动调用 os.fork os.exec 之类 (希望这里不要说我忘记加括号了) 多 goroutine 是否在同一个进程下. 因为我有一个定时任务, 会 定期修改环境变量 同时要求其他 goroutine 实时读取这个环境变量. @错了的花, 见谅. |
31
chaleaochexist OP |
32
pkoukk 2023-10-17 16:17:55 +08:00 1
我见识少,有什么语言的多线程是通过多进程实现的嘛?
|
33
ysc3839 2023-10-17 16:18:45 +08:00 via Android
@chaleaochexist 26 楼已经回答了,没问题
|
34
chaleaochexist OP |
35
chaleaochexist OP |
36
importlau 2023-10-17 16:21:34 +08:00
@chaleaochexist 是的, 同一个进程下的。
|
37
ysc3839 2023-10-17 16:21:46 +08:00 via Android
@pkoukk 用户模式线程或者说协程不能用多进程来实现,但是一些子逻辑是可以用多进程的。
因为 Unix 有 fork 可以很方便地保留数据启动新进程,有些程序的子逻辑(比如处理客户端的请求)就会 fork 一下再处理。 |
38
chaleaochexist OP |
39
chaleaochexist OP @Ericcccccccc
标题和内容完全不搭啊... 回到你的问题, 实时修改环境变量能不能生效得看这个值是啥时候读的. 假设两个 goroutine 一个随机写 一个随机读 要求每次都读到最新的环境变量. 如果这两个 goroutine 在两个进程下. 默认是不行的. |
40
proxytoworld 2023-10-17 16:25:29 +08:00
@chaleaochexist 同一个进程 环境变量是一份的
|
41
mightybruce 2023-10-17 16:26:12 +08:00
多个 goroutine 并不对应多进程,除非你通过 syscall 在代码主动去创建进程。
你改了环境变量,其他 goroutine 是感知不到的, 除非再次主动去读。 多个 goroutine 在一个进程中。 |
42
e7 2023-10-17 16:35:36 +08:00
以前找工作的时候经常遇到面试官问类似这种问题,一脸懵逼
|
43
awalkingman 2023-10-17 16:39:03 +08:00
你是不是想问不同 goroutine 之间的通信机制?
|
44
bler 2023-10-17 16:39:05 +08:00 1
我大概明白楼主是啥意思,楼主应该是想问,main1.go 和 main2.go 独立运行,会不会被 go 语言分配到同一个进程之中。我被 python 的 scrapy 框架坑过,scrapy crawl 命令运行爬虫的时候,scrapy crawl spider1 和 scrapy crawl spider2 是运行在同一个进程之下的,pipeline 的类变量在两个爬虫中会共用,估计楼主应该是遇到类似的问题了
|
45
xdeng 2023-10-17 16:39:44 +08:00
单进程是常态吧
|
46
xsen 2023-10-17 16:43:20 +08:00
|
47
Immortan 2023-10-17 16:49:03 +08:00 2
- Golang 不是单进程的,GOMAXPROCS 默认等于运行时机器的 runtime.NumCPU()
- 但是开发者不用关心,这是 OS 层面的抽象,OS 会保证即使实际运行在多核上,其行为也和运行在单核上一样,比如环境变量的变化。 - 环境变量是 OS 管理的,读取、修改环境变量都需要通过系统调用进入内核态,自然会在所有 goroutine 中生效。 - 一般非常少会通过环境变量的运行时改变来控制代码行为,尤其像 Golang 这种原生对并发支持力度就很大的语言。如上所述,环境变量的读取需要通过系统调用,某种程度上是个"很贵"的操作。 |
48
wOuv7i4e7XxsSOR1 2023-10-17 16:49:55 +08:00
这个问题槽点太多,不知道该怎么回答
|
49
LindsayZhou 2023-10-17 16:51:09 +08:00 1
是不是可以这样想,goroutine 之间是可以共享全局变量的,那么表示所有的 goroutine 是共用一套内存地址空间的。
而环境变量存储的位置,如果我没记错,是在程序入口前面一小段的内存里面,既然所有的内存空间是共享的,那么这段环境变量的内存也是共享的。 这样就摆脱了线程进程的概念,不用考虑那些了。 (如果是进程,那内存页就是 COW 了) |
50
ygtq 2023-10-17 16:53:42 +08:00
@chaleaochexist 多 goroutine 是否在同一个进程下? 我的理解是,肯定在。因为你没有主动 fork ,golang 也不会主动多开一个进程,go 只是一个静态编程语言,换言之你用 c/c++写,编译生成可执行程序,代码不主动开进程,语言不会开的啊
|
51
kiripeng 2023-10-17 16:58:32 +08:00
Happens-Before 原则
|
52
EspoirBao 2023-10-17 17:04:20 +08:00
看到单进程的时候突然小脑猥琐了一下,在想是什么情况下需要改多进程的环境变量,进程一般都属于 OS 级别控制的吧???
|
53
zmaplex 2023-10-17 17:31:25 +08:00 via Android
不管什么语言,只要不 fork 就是天王老子来了都是单进程。要多进程,只要不主动加锁限制,都可以多进程运行(系统限制除外)
|
54
standchan 2023-10-17 17:51:35 +08:00
你没 exec 操作,goroutine 就是一定是单进程,然后 goroutine 是在语言层面复用 os 的线程。此外,我写了 demo 代码,结果是其他 goroutine 也可以读到新修改的环境变量,前提的实时去读。
|
55
RedisMasterNode 2023-10-17 18:05:09 +08:00
@dw2693734d 楼主问这个问题肯定是有他背景,例如 Python 进程经常用 Gunicorn 或者 uwsgi 托管,这些都会导致应用程序以多个进程形式运行。
我觉得大家回答不用太过抠字眼了...其实就是个快问快答,但是较真(较真不代表不好)的人很多,才搞得帖子这样... 包括一些什么可以 os.Exec 扩展多进程,拜托,别的语言一样可以,补充这种信息对回答问题一点帮助都没有,不如直接点明 Go 和其他语言的区别在哪里简洁明了。 |
56
ding2dong 2023-10-17 18:21:37 +08:00
当然可以啊,goroutine 是线程不是进程
|
57
aisk 2023-10-17 19:03:19 +08:00
@RedisMasterNode 他背景他说了,一个 goroutine 里设置环境变量另外一个读不到,然后不怀疑自己代码有 bug ,怀疑 go 是多进程运行不同 goroutine 。
|
58
chaleaochexist OP @aisk 不是怀疑 我还没开始写呢.
提前做点调查. |
59
chaleaochexist OP @standchan 这个东西不能通过 demo 去验证.
当然了严谨一点说 可以证伪. 但是不能验证正确. 譬如 runtime 有一种机制, 当 goroutine < 5. 或者换个说法 count(runtime) < 5 是单进程, >=5 是多进程模式. 所以我发帖上来问问, 不知道为什么楼上一堆冷嘲热讽. |
60
chaleaochexist OP |
61
chaleaochexist OP @kiripeng 大佬这是另一个问题了.
大佬能通俗易懂的解释一下 什么是 Happens-Before 吗? |
62
chaleaochexist OP @ygtq go 和 c++的区别是 go 有一个 goroutine 这个东西是由 runtime 控制的. 所以才上来确认一下.
通常来说确实应该是单进程. |
63
aisk 2023-10-17 21:24:15 +08:00
@chaleaochexist 动手测试一分钟,群里讨论一整天。
|
64
chaleaochexist OP @aisk 这个东西不能通过 demo 去验证.
当然了严谨一点说 可以证伪. 但是不能验证正确. 譬如 runtime 有一种机制, 当 goroutine < 5. 或者换个说法 count(runtime) < 5 是单进程, >=5 是多进程模式. 所以我发帖上来问问, 不知道为什么楼上一堆冷嘲热讽. |
65
standchan 2023-10-17 22:16:34 +08:00
我没有找到你说的 golang runtime 当协程数量大于一定数目就变成了多进程模式。你在哪里看到的资料能发出来看一下吗?我认为多进程肯定不合理,进程之间的通信要比协程之间的通信复杂太多了,还涉及到了各种同步等等乱七八糟的。另外,你起初问的问题确实特别让人费解,标题和正文我找不到逻辑的相关性
|
66
standchan 2023-10-17 22:26:03 +08:00
另外 runtime 对 goroutine 的控制也是基于系统进程里面进行的。它是在进程下面的,当然 exec 会生成新的进程,但生成的进程和 golang 程序所在的进程完全没关系。runtime 也不可能凌驾于进程们之上去管理多个进程。go 是面向云原生高并发,如果是你说的多进程模式,那延迟会高很多很多。
|
67
aisk 2023-10-17 22:26:19 +08:00
@chaleaochexist 错的不是你。
|
68
chaleaochexist OP |
69
standchan 2023-10-17 23:52:25 +08:00
@chaleaochexist #68 嗯嗯,那现在应该知道结果了就行了。另外,问题的描述可以再提升一下,看起来真的会让人有点懵。
|
70
voidmnwzp 2023-10-18 00:05:03 +08:00
…你告我哪个语言不是单进程的
|
71
qwq11 2023-10-18 01:13:28 +08:00 via Android
op 去看下操作系统,环境变量是在进程启动的时候被 OS 压到程序的栈里的,所以说是静态的,而不是动态读取。如果你说的是在同一进程下的 goroutine ,显然不会生效,如果你说的是不同进程的 goroutine ,并且在修改完了之后才启动新进程,那答案是会生效
你在 #30 说的情况,答案是不会生效 |
72
chaleaochexist OP @qwq11 啊??
什么? ``` package main import ( "fmt" "os" "time" ) func main() { os.Setenv("FOO", "1") fmt.Println(os.Getenv("FOO")) go func() { os.Setenv("FOO", "2") }() time.Sleep(1 * time.Second) fmt.Println(os.Getenv("FOO")) } ``` |
73
CrazyMonkeyV 2023-10-18 08:42:00 +08:00
@chaleaochexist 前面我觉得你菜就算了,谁没菜过?看到后面有点逆天。程序员不是自己搞 demo 来证明,靠不明需求的论坛? 6666
|
74
Masoud2023 2023-10-18 09:34:42 +08:00
|
75
bler 2023-10-18 09:35:38 +08:00
@bler 我更新一下我的回答,”pipeline 的类变量在两个爬虫中会共用“,这是错误的,虽然两个爬虫在同一进程中,但是两个爬虫类变量是隔离的
|
76
chaleaochexist OP @Masoud2023 因为我 B 了一些人不知道你说的 72 楼是哪个.
也不算共享内存吧. 就是在不停机的情况下 动态切换 kafka 的配置. 且 if flag == 1 then 从环境变量读配置 else 从数据库读配置. 那我之前的想法是当从数据库读配置之后, 写到环境变量中, 这样其他代码就不用动了. 然后就发帖问问题了. 说得通吗? |
77
pkoukk 2023-10-18 10:34:16 +08:00
@chaleaochexist #76
有这种需求,一般我们会搞个 etcd ,redis 也行啊。 你这个玩法让人真是搞不懂,线上部署的时候直接跑二进制,不用 docker ? 不用 docker 隔离环境罢了,还用环境变量,这么信任跑在这台机器上的其它服务? 说到进程问题,我用过的语言里,只要你不 fork ,它们就是共用完全相同的上下文和内存,别管他在 cpu 里有几个实例,那是 os 的事情,和语言无关。 |
78
qwq11 2023-10-18 10:44:19 +08:00
@chaleaochexist #72 你是对的,去研究了下 linux 确实可以修改本进程的环境变量,修改之后 OS 会重新给进程分配环境变量表,这点有点出乎意料
#76 的需求建议用变量存,把 os.Getenv 换成 KafkaConfigProvisioner.GetConfig 也用不了多少时间,比你发帖回帖快,用环境变量还得上信号量或者读写锁 |
79
chaleaochexist OP |
80
chaleaochexist OP |
81
tonghuashuai 2023-10-18 10:52:22 +08:00
跟 GOMAXPROCS 有关吧,GOMAXPROCS 默认为 CPU 核心数,GOMAXPROCS 参数来确定线程数。
然后 Go 运行时调度使用 m:n 策略,复用 m 个 goroutine 到 n 个线程。 |
82
chaleaochexist OP @qwq11 还有就是其实不需要信号量和读写锁. 这个和我的具体业务有关. 具体就不展开讲了.
|
83
Jooeeee 2023-10-18 11:14:27 +08:00
语言跟操作系统是两码事儿,进程分为线程,线程使用一小块内存构造 goroutine ,由于进程的所有现成共享内存,因此 goroutine 可以在不同的线程上跑。golang 可以在 goroutine 中启动新的进程
|
84
mightybruce 2023-10-18 15:23:50 +08:00
你选择用环境变量实现,可以说是非常差的方式, 有非常多的方式可以实现
1. 服务通过读取一些第三方配置中心来动态改变,比如 etcd, nacos 2. 服务中直接写一个 http 控制服务,接受请求直接切换。 |
85
dyllen 2023-10-31 10:36:06 +08:00 1
单进程多线程,编译一个 exe 出来,只有一个进程,系统线程默认是和 cpu 核数是相等的,一个 goroutine 的执行是在线程里面执行的,不一定是哪个线程。go 的 goroutine 是共享内存的,一个全局变量可以多个 goroutine 修改和读取,会互相影响。
|