The append of the Go language is not always thread-safe

Source: Internet
Author: User
# # example problem I often see some bugs due to the lack of append on the slice in the thread security. Here's a simple example using unit tests. This test has two threads that perform append operations on the same slice. If you use '-race ' flag to perform this unit test, it works better. "' Gopackage mainimport (" Sync "" testing ") Func Testappend (t *testing. T) {x: = []string{"Start"}WG: = Sync. WAITGROUP{}WG. ADD (2) go func () {defer WG. Done () Y: = append (x, "Hello", "World") T.Log (Cap (y), Len (y))} () go func () {defer WG. Done () Z: = Append (X, "Goodbye", "Bob") T.Log (Cap (z), Len (z))} () WG. Wait ()} "Now, let's just slightly modify the code to give the slice named ' X ' to reserve some capacity in the creation. The only place to change is line 9th. "' Gopackage mainimport (" Testing "" Sync ") func testappend (t *testing. T) {x: = make ([]string, 0, 6) WG: = Sync. WAITGROUP{}WG. ADD (2) go func () {defer WG. Done () Y: = append (x, "Hello", "World") T.Log (len (y))} () go func () {defer WG. Done () Z: = Append (X, "Goodbye", "Bob") T.Log (Len (z))} () WG. Wait ()} "If we carry the test with '-race ' flag, we can notice a competitive condition. "< go test-race. ==================warning:data racewrite at 0x00c4200be060 by Goroutine 8:_/tmp. TESTAPPEND.FUNC2 ()/tmp/main_test.go:20 +0xcbprevious write at 0x00c4200be060 by Goroutine 7:_/tmp. TESTAPPEND.FUNC1 ()/tmp/main_test.go:15 +0xcbgoroutine 8 (running) created at:_/tmp. Testappend ()/tmp/main_test.go:18 +0x14ftesting.trunner ()/usr/local/cellar/go/1.10.2/libexec/src/testing/ testing.go:777 +0x16dgoroutine 7 (running) created at:_/tmp. Testappend ()/tmp/main_test.go:13 +0x105testing.trunner ()/usr/local/cellar/go/1.10.2/libexec/src/testing/ testing.go:777 +0x16d====================================warning:data racewrite at 0x00c4200be070 by Goroutine 8:_/ Tmp. TESTAPPEND.FUNC2 ()/tmp/main_test.go:20 +0x11aprevious write at 0x00c4200be070 by Goroutine 7:_/tmp. TESTAPPEND.FUNC1 ()/tmp/main_test.go:15 +0x11agoroutine 8 (running) created at:_/tmp. Testappend ()/tmp/main_test.go:18 +0x14ftesting.trunner ()/usr/local/cellar/go/1.10.2/libexec/src/testing/ testing.go:777 +0x16dgoroutine 7 (finished) created at:_/tmp. Testappend ()/tmp/main_test.go:13 +0x105testing.trunner ()/usr/local/cellar/go/1.10.2/libexec/src/testing/ testing.go:777 +0x16d==================---FAIL:testappend (0.00s) Main_test.go:16:2main_test.go:21:2testing.go:730:race detected during execution of TestFAILFAIL _ /tmp 0.901s ' # # explains why the test failed to understand why this failure will happen, please take a look at the memory layout of this old example ' x '! [] (https://raw.githubusercontent.com/studygolang/gctt-images/master/go-append-is-not-always-thread-safe/ x-starts-with-no-capacity-to-change.png) x does not have enough capacity to modify the Go language discovery does not have enough memory space to store ' "Hello", "World" and "Goodbye", "Bob", Then allocate the new memory to ' y ' and ' z '. Data contention does not occur when a multi-process reads memory, ' x ' is not modified. There is no conflict, there is no competition. [] (https://raw.githubusercontent.com/studygolang/gctt-images/master/go-append-is-not-always-thread-safe/ Z-and-y-get-their-own-memory.png) z and y get new memory space in the new code, things are different! [] (https://raw.githubusercontent.com/studygolang/gctt-images/master/go-append-is-not-always-thread-safe/ X-has-capacity-for-more.png) x has more capacity here, go notes that there is enough memory to store ' "Hello", "World", and another coprocessor has found enough space to store ' "Goodbye", "Bob", This competition occurs because both of these processes are trying to write to the same memory space, and no one knows who the winner is. [] (https://raw.githubusercontent.com/studygolang/gctt-images/master/go-append-is-not-always-thread-safe/ Who-wins.png) who won?? This is a feature of the Go language, not a bug, and ' append ' does not force each call to request new memory. It allows the user to perform ' append ' operations within the loop without destroying the garbage collection mechanism. The disadvantage is that you have to be aware of the slice operations on multiple processes. # # The cognitive roots of this bug I believe that the bug exists in Go to save simplicity, put many concepts into slice, and the thought process seen by most developers is: 1. ' X=append (x, ...) ' It looks like you're going to get a new slice. 2. Most functions that return values do not change their input. 3. We use ' append ' usually to get a new slice. 4. Mistakenly considers append to be read-only. # # Cognition This bug is worth noting that if the first variable that is ' append ' is not a local variable (translator: local variable, that is, the variable is in the same block as the append). This bug usually occurs when a variable with a append operation exists in a struct, and the struct is passed in through a function. For example, a struct can have a default value that can be append by individual requests. Be careful to append a variable that shares memory, or this memory space (variable) is not currently exclusive to the coprocessor. # # The simplest workaround is to not use the first variable of the shared state for append. Instead, ' make ' a new ' slice ' according to your needs, using this new slice as the first variable of append. The following is a revised version of the failed test example, where the workaround is to use [copy] (https://golang.org/pkg/builtin/#copy). "' Gopackage mainimport (" Sync "" testing ") Func Testappend (t *testing. T) {x: = make ([]string, 0, 6) x = append (x, "Start") WG: = Sync. WAITGROUP{}WG. ADD (2) go func () {defer WG. Done () Y: = make ([]string, 0, Len (x) +2) y = append (y, x ...) y = append (y, "Hello", "World") T.Log (Cap (y), Len (y), y[0])} () go func () {defer WG. Done () Z: = Make([]string, 0, Len (x) +2) z = append (z, x ...) z = append (Z, "Goodbye", "Bob") T.Log (Cap (z), Len (z), Z[0])} () WG. Wait ()} "append the local variable for the first time

via:https://medium.com/@cep21/gos-append-is-not-always-thread-safe-a3034db7975

Author: Jack Lindamood Translator: Lightfish-zhang proofreading: polaris1119

This article by GCTT original compilation, go language Chinese network honor launches

This article was originally translated by GCTT and the Go Language Chinese network. Also want to join the ranks of translators, for open source to do some of their own contribution? Welcome to join Gctt!
Translation work and translations are published only for the purpose of learning and communication, translation work in accordance with the provisions of the CC-BY-NC-SA agreement, if our work has violated your interests, please contact us promptly.
Welcome to the CC-BY-NC-SA agreement, please mark and keep the original/translation link and author/translator information in the text.
The article only represents the author's knowledge and views, if there are different points of view, please line up downstairs to spit groove

365 Reads
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.