This is my first and second post as an engineer. I had the opportunity to write an exclusive control mechanism in Go, so I will record it. This time, we will create an exclusive control mechanism using two methods.
This time, using a table as a shared resource, when processing is performed on the table from multiple processes, a mechanism is created to prevent subsequent processes from operating the table until the previous process is completed. I will continue.
First, try updating the table at the same time using Goroutine without exclusive control. (sync.WaitGroup is for waiting the main goroutine. For more information here.)
var w sync.WaitGroup
func main() {
w.Add(2)
go update()
go update()
w.Wait()
}
func update() {
defer w.Done()
for i := 0; i <= 10; i += 5 {
fmt.Println("tbl update:", i*10, "%")
time.Sleep(time.Second)
}
}
// tbl update: 0 %
// tbl update: 0 %
// tbl update: 50 %
// tbl update: 50 %
// tbl update: 100 %
// tbl update: 100 %
You can see that the two processes are updating the table at the same time. This time, we will create a mechanism to obtain the following output so that the subsequent update will be performed after the previous update is completed.
// tbl update: 0 %
// tbl update: 50 %
// tbl update: 100 %
// tbl update: 0 %
// tbl update: 50 %
// tbl update: 100 %
First, from sync.Mutex.
//The main function is the same as above
var m sync.Mutex
func update() {
defer w.Done()
defer m.Unlock()
m.Lock()
for i := 0; i <= 10; i += 5 {
fmt.Println("tbl update:", i*10, "%")
time.Sleep(time.Second)
}
}
// tbl update: 0 %
// tbl update: 50 %
// tbl update: 100 %
// tbl update: 0 %
// tbl update: 50 %
// tbl update: 100 %
Declare UnLock ()
and Lock ()
at the beginning of update ()
.
Subsequent goroutines cannot apply Lock ()
until the preceding goroutines UnLock ()
(until the processing of the function is completed), and as a result, wait for the processing of the preceding goroutines to finish.
You can see that the output is as you intended.
Although sync.Mutex is very simple and straightforward, it does only one process. It's a little different from this scenario, but it seems difficult to create a mechanism such as "to reduce the load on the server, prevent more than 1000 processes from running at the same time".
Since this is my first time using a semaphore, I will write about what a semaphore is.
The semaphore is one of the exclusive control mechanisms and models the operation of railway tracks. (Semaphore means traffic light in Japanese) It was created to control the shared resources of railroad tracks so that they are not used at the same time. A semaphore consists of three semaphore variables, a P operation, and a V operation.
--Semaphore variables --Number of processes that can access shared resources ――It will not be negative --A semaphore variable that takes only 0 or 1 is called a ** binary semaphore **, and one that takes 0 to N is called a ** general semaphore **. --P operation --Decrement semaphore variables --A process secures shared resources --V operation --Increment the semaphore variable --A process releases shared resources
This scenario is a binary semaphore, and it seems that you need to perform a P operation at the beginning of update ()
and a V operation at the end.
golang.org/x/syncを使って実装します。
const semaphoreCnt = 1
var s *semaphore.Weighted = semaphore.NewWeighted(semaphoreCnt)
func update() {
defer w.Done()
defer s.Release(1) //V operation Increases the semaphore variable by 1.
s.Acquire(context.TODO(), 1) //P operation: Decrease the semaphore variable by 1.
for i := 0; i <= 10; i += 5 {
fmt.Println("tbl update:", i*10, "%")
time.Sleep(time.Second)
}
}
// tbl update: 0 %
// tbl update: 50 %
// tbl update: 100 %
// tbl update: 0 %
// tbl update: 50 %
// tbl update: 100 %
golang.org/x/sync
のAcquire()
がP操作に,Release()
がV操作にあたります。
Exclusive control is realized by defining a semaphore variable with semaphore.Weighted
and increasing or decreasing it usingAcquire ()
andRelease ()
.
また、golang.org/x/sync
では、Acquire()
,Release()
でセマフォ変数をいくつ増減させるかを調節することが出来ます。(今回は2値セマフォのため、それぞれ1増減となっています。)
This allows you to define the processing weights for each process.
golang.org/x/sync
を使うことでsync.Mutex
と比べ、より複雑な排他制御の仕組みを作ることができます。
Recommended Posts