Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is lock necessary when GOMAXPROCS is 1

Tags:

go

The GOMAXPROCS variable limits the number of operating system threads that can execute user-level Go code simultaneously.

So, if GOMAXPROCS is 1, no matter how many goroutines I have, it is safe to access variable (like map) from different goroutines without any lock. Correct?

like image 547
Mr.Wang from Next Door Avatar asked Dec 19 '22 16:12

Mr.Wang from Next Door


1 Answers

The short answer is, "no" it is not safe. The long answer is really too long to explain in enough detail here, but I'll give a short summary and some links to articles which should help you put the pieces together.

Let's differentiate between "concurrent" and "parallel" first. Consider two functions. Running in parallel they can both be executing at the same instant on separate processors. Running concurrently either, or both, or neither may be executing but both are able to execute. If they are concurrent but not parallel then they are switching—and without channels or locks we cannot guarantee the sequence in terms of which gets where first.

It may be weird to think about "concurrent but not parallel" but consider that the opposite is quite unremarkable, parallel but not concurrent; my text editor, terminal and browser are all running in parallel but are most definitely not concurrent.

So if two (or 20,000) functions have access to the same memory, say one writes and one reads, and they are running concurrently, then perhaps the write happens first, perhaps the read happens first. There are no guarantees unless we take responsibility for the scheduling/sequencing, hence locks and channels.

Setting GOMAXSPROCS to greater than 1 makes it possible for a concurrent program to run in parallel, but it may not, all concurrent goroutines may be on one CPU thread, or they may be on multiple. Thus setting GOMAXPROCS to 1 is no guarantee that concurrent processes are safe without locks or channels to orchestrate their execution.

Threads are [typically] scheduled by the operating system. See Wikipedia or your favorite repository of human knowledge. Goroutines are scheduled by Go.

Next consider this:

Even with [a] single logical processor and operating system thread, hundreds of thousands of goroutines can be scheduled to run concurrently with amazing efficiency and performance.

and this:

The problem with building concurrency into our applications is eventually our goroutines are going to attempt to access the same resources, possibly at the same time. Read and write operations against a shared resource must always be atomic. In other words reads and writes must happen by one goroutine at a time or else we create race conditions in our programs.

from this article, which explains the difference really well and references some other material you may want to look up (the article is somewhat outdated, as GMAXPROCS no longer defaults to 1, but the general theory is still accurate).

And finally, Effective Go can be daunting when you're starting out but is a must-read. Here is the explanation of concurrency in Go.

like image 71
Snowman Avatar answered Jan 15 '23 00:01

Snowman