为什么共享int变量在go例程中递增时会显示原子行为?

时间:2015-11-14 18:30:17

标签: go

当我在下面运行下面的代码片段时,它看起来总是打印值20000000.当我创建更多的go例程来增加没有锁定的计数器时,它显示了类似的行为。但是不存在某种竞争条件吗?谢谢!

package main

import "fmt"

const (
N_INCREMENTS = 10000000
)

func main() {

var counter int = 0
donechan := make(chan bool)

go func(done chan<- bool) {
    for i := 0; i < N_INCREMENTS; i++ {
        counter++
    }
    done <- true
}(donechan)

for i := 0; i < N_INCREMENTS; i++ {
    counter++
}

_ = <-donechan

fmt.Println("Count: ", counter)
}

1 个答案:

答案 0 :(得分:1)

runtime.GOMAXPROCS(0)将报告可以并行运行的goroutine的数量。如果值为1,您可能不会观察到不同步 package rembrandt.bin import rembrandt.obj.* import saskia.bin.Configuration import rembrandt.io.* import org.apache.log4j.* import org.apache.commons.cli.* import java.util.jar.Manifest import java.util.jar.Attributes class Rembrandt { /** * Main method. */ static void main(args) { def rembrandt, conf, conffilepath Options o = new Options() o.addOption("conf", true, "Configuration file") o.addOption("gui", true, "Activates a graphic GUI") o.addOption("help", false, "Gives this help information") CommandLineParser parser = new GnuParser() CommandLine cmd = parser.parse(o, args) if (cmd.hasOption("help")) { HelpFormatter formatter = new HelpFormatter(); formatter.printHelp( "java rembrandt.bin.Rembrandt", o ) System.exit(0) } if (!cmd.hasOption("conf")) { conffilepath = Configuration.defaultconf log.info "No configuration file given. Using default configuration file." } else { conffilepath = cmd.getOptionValue("conf") log.info "Configuration file $conffilepath given." } conf = Configuration.newInstance(conffilepath) rembrandt = new Rembrandt(conf) log.info "Rembrandt version ${Rembrandt.getVersion()}. Welcome." if (cmd.hasOption("gui")) { RembrandtGui gui = new RembrandtGui(rembrandt, conf)//) gui.start() log.info "Rembrandt GUI started." } else { log.info "Invoking reader ${rembrandt.inputreader.class.name} to parse the input stream." List<Document> docs = rembrandt.loadDocuments() log.info "Got ${docs.size()} doc(s). " // give labels if the doc does not have... String docid_header if (rembrandt.inputFileName) docid_header = rembrandt.inputFileName else docid_header = 'stdin' rembrandt.printHeader() /* stats stuff */ def stats = new DocStats(docs.size()) stats.begin() docs.eachWithIndex { doc, i-> if (!doc.docid) doc.docid = docid_header+"-"+(i+1) stats.beginDoc(doc.docid) doc = rembrandt.releaseRembrandtOnDocument(doc) rembrandt.printDoc(doc) stats.endDoc() stats.printMemUsage() } stats.end() rembrandt.printFooter() log.info "All Done. Have a nice day." } } } 变量的任何“副作用”。

如果您首先在程序开头将其设置为counter

2

您将立即看到效果:

runtime.GOMAXPROCS(2)

如果您想获得竞争条件的证据,请提供Count: 10319575 参数。输出-race

-race

(请注意,竞争检测器仅适用于64位Go分布。)

在Go操场上,GOMAXPROCS默认为================== WARNING: DATA RACE Read by goroutine 6: main.main.func1() V:/workspace/IczaGo/src/play/play.go:20 +0x48 Previous write by main goroutine: main.main() V:/workspace/IczaGo/src/play/play.go:26 +0xef Goroutine 6 (running) created at: main.main() V:/workspace/IczaGo/src/play/play.go:23 +0xbc ================== 。此行将打印上一个值并将其设置为1

2

输出(在Go Playground上尝试):

fmt.Println("Previous GOMAXPROCS:", runtime.GOMAXPROCS(2))

另请注意,GOMAXPROCS在1.5之前的Go分布中设置为Previous GOMAXPROCS: 1 Count: 12844130 。从1.5开始,GOMAXPROCS的默认值是运行程序的计算机上可用的CPU核心数。