WaitGroups are deterministic in that sense. Whether they are all released at once (there is no such thing as “at once” in practice) you have a race.
You can restructure this to avoid the race. You should Add() to to the stage 1 and 2 wait groups after the Wait() returns and before you Wait() on the stage 2. > On Jan 16, 2021, at 6:05 PM, Pete Wilson <peter.wil...@bsc.es> wrote: > > Jake > > Thanks for thoughts > > My approach made the assumption that Wait() worked as advertised - all the > goroutines are released when the Wait() hits zero. > What you’re pointing out is that Wait() is in some sense racy itself. > I had assumed that no goroutine in a waitgroup was ‘released' until they all > were. > Your explanation says they’re released in some non-deterministic manner. And > nobody can tell when. > > If the waitgroup is being used in the classic manner (in essence, goroutine A > waiting for a bunch of other goroutines to signal completion, with those > other routines doing nothing after completion, then the ’non-deterministic > release’ semantics is fine. But - obviously - it doesn’t work for my purposes. > > This is the likely situation, therefore. > > I’m trying to avoid using channel communication to separate the ‘phases’ (the > computations interspersed by barriers) for efficiency reasons. > > I think the approach is sound - barriers are a known thing - but my > misunderstanding of Wait() means that my barrier isn’t sound at all. So I > shall seek to build a better barrier, and also measure channel performance - > because I think to make the barrier work as desired, I need to construct it > from two waitgroups, and whack one then the other being careful about resets. > > But that with extra path length I should also look again at channels. > > — P > > >> On Jan 16, 2021, at 5:23 PM, golang-nuts@googlegroups.com wrote: >> >> golang-nuts@googlegroups.com Google Groups >> Topic digest >> View all topics >> Waitgroup problem - 3 Updates >> possible inconsistency in the embed package documentation - 11 Updates >> GODOC: how to create a reference to another definition in a comment? - 1 >> Update >> `go list` across multiple modules? - 2 Updates >> super large virtual memory allocation for simplest golang apps, why? - 1 >> Update >> [ANN] go-featureprocessing v1.0.0 - 1 Update >> Context on one-shot structs - 1 Update >> Waitgroup problem >> Pete Wilson <peter.wil...@bsc.es>: Jan 16 10:28AM -0600 >> >> Gentlepersons >> >> I asked for advice on how to handle a problem a few days ago, and have >> constructed a testbed of what I need to do, using WaitGroups in what seems >> to be a standard manner. >> >> But the code fails and I don’t understand why. >> >> The (simple version of) the code is at https://play.golang.org/p/-TEZqik6ZPB >> <https://play.golang.org/p/-TEZqik6ZPB> >> >> In short, what I want to do is to have a controller goroutine (main) plus >> some number of worker goroutines >> >> I implement a Barrier function which operates on a properly-initialised >> waitgroup. >> >> The Barrier function simply does Done() then Wait() >> >> What I want is that each worker does a two-phase operation >> - wait until everybody has passed a start barrier >> - do some work >> - wait until everybody has passed an end barrier >> - do some work >> >> .. doing this some number of times >> >> In parallel, main has created and initialised the start and end waitgroups >> wgstart and wgend >> main has then created the worker goroutines (in the real thing I want >> roughly one worker per core, so there’s also some setting of GOMAXPROCS) >> main then enters a loop in which it >> >> - waits until everbody including it has passed the start barrier >> - resets the start barrier >> - waits until everybody has bassed the end barrier >> - resets the end barrier >> >> This behaviour is observed, except the code panics, both in the playgorund >> and on my machine. Typical failure is: >> >> ----------- [2] main about to barrier start --------------- w[7] enters >> barrier startpanic: sync: WaitGroup is reused before previous Wait has >> returned goroutine 10 [running]: sync.(*WaitGroup).Wait(0xc00002c030) >> /usr/local/go-faketime/src/sync/waitgroup.go:132 +0xae main.Barrier(0x4, >> 0x4bef21, 0x3, 0xc00002c030) /tmp/sandbox686473236/prog.go:51 +0x12b >> main.worker(0x4, 0xc00002c020, 0xc00002c030, 0xa) >> /tmp/sandbox686473236/prog.go:35 +0x309 created by main.main >> /tmp/sandbox686473236/prog.go:78 +0x295 >> >> What have I misunderstood and done wrongly? >> >> Thanks! >> >> — P >> >> WARNING / LEGAL TEXT: This message is intended only for the use of the >> individual or entity to which it is addressed and may contain information >> which is privileged, confidential, proprietary, or exempt from disclosure >> under applicable law. If you are not the intended recipient or the person >> responsible for delivering the message to the intended recipient, you are >> strictly prohibited from disclosing, distributing, copying, or in any way >> using this message. If you have received this communication in error, please >> notify the sender and destroy and delete any copies you may have received. >> >> http://www.bsc.es/disclaimer >> >> >> >> >> >> >> http://bsc.es/disclaimer >> "jake...@gmail.com" <jake6...@gmail.com>: Jan 16 08:59AM -0800 >> >> There may be other problems as well, but the WaitGroup.Add >> <https://golang.org/pkg/sync/#WaitGroup.Add> documentation says: >> " If a WaitGroup is reused to wait for several independent sets of events, >> new Add calls must happen after all previous Wait calls have *returned*." >> >> You have a race condition. What I believe is happening is the following: >> >> - The last goroutine calls `Barrier(w, "start", wgstart)`. That calls >> barrier.Done(). It then calls Wait(), but Wait() has not returned. >> - Meanwhile main() calls `Barrier(threads, "start", &wgstart)`. The >> Wait() in that call returns because all the goroutines have called Done(). >> - main() calls `wgstart.Add(threads + 1)` >> - The goroutine from above is still in the Wait() call, hence the >> panic. >> >> There is also another possible scenario, that is not causing the panic I >> see, but could cause incorrect behavior: >> >> - The last goroutine calls `Barrier(w, "start", wgstart)`. That calls >> barrier.Done(). >> - Meanwhile main() calls `Barrier(threads, "start", &wgstart)`. The >> Wait() in that call returns because all the goroutines have called Done(). >> - main() calls `wgstart.Add(threads + 1)` >> - The goroutine from above now calls Wait(), but since Add was already >> called, it blocks. That goroutine is now 'stuck', because Wait() will >> never return, which will in turn end up blocking all the other goroutines >> eventually. >> >> Honestly, I think you need to rethink your whole model. >> >> Hope that helps. >> On Saturday, January 16, 2021 at 11:28:59 AM UTC-5 Pete Wilson wrote: >> >> Brian Candler <b.cand...@pobox.com>: Jan 16 01:02PM -0800 >> >> On Saturday, 16 January 2021 at 16:28:59 UTC Pete Wilson wrote: >> >> > In short, what I want to do is to have a controller goroutine (main) plus >> > some number of worker goroutines >> >> This doesn't answer your question, but if you haven't seen it already I >> recommend this video about concurrency patterns in go: >> https://www.youtube.com/watch?v=5zXAHh5tJqQ >> >> All of it is well worth watching, but an example of using a semaphore >> channel instead of a worker pool starts at 32:15. >> Back to top >> possible inconsistency in the embed package documentation >> Manlio Perillo <manlio.peri...@gmail.com>: Jan 16 10:10AM -0800 >> >> I'm reading the https://tip.golang.org/pkg/embed/ package documentation and >> I found a possible inconsistency. >> >> At the end of https://tip.golang.org/pkg/embed/#hdr-Directives: >> "Patterns must not match files outside the package's module, such as >> ‘.git/*’ or symbolic links" >> and >> "Patterns must not contain ‘.’ or ‘..’ path elements nor begin with a >> leading slash" >> >> It seems to me that the first phrase is not necessary, since the second >> phrase prevents matching files outside the package module. >> >> >> Thanks >> Manlio Perillo >> Axel Wagner <axel.wagner...@googlemail.com>: Jan 16 07:24PM +0100 >> >> I don't think they do. There are two examples in the first phrase, which >> are not excluded by the second - the ".git" directory and a symbolic link >> (pointing outside of the module). >> >> On Sat, Jan 16, 2021 at 7:11 PM Manlio Perillo <manlio.peri...@gmail.com> >> wrote: >> >> Dmitri Shuralyov <dmits...@golang.org>: Jan 16 10:28AM -0800 >> >> I think both are needed, they don't overlap. Note that the second phrase >> says "must not contain '.' or '..' path *elements*", emphasis them being a >> complete path element. So "./git" is disallowed by the second phrase, but >> ".git" is not. >> >> On Saturday, January 16, 2021 at 1:10:47 PM UTC-5 manlio....@gmail.com >> wrote: >> >> Axel Wagner <axel.wagner...@googlemail.com>: Jan 16 07:29PM +0100 >> >> To put it another way: >> >> The second phrase is a lexical requirement about the pattern. It must not >> contain a . or .. element - whether or not the result is included in the >> module (e.g. "foo/../foo/bar" is not allowed either, even though it's >> equivalent to "foo/bar"). >> >> But, a lexical path *in* the module might still refer to a file not >> included in it it - either by a symlink, or by being in the .git directory >> (and maybe other cases I'm unaware of). So, the first phrase excludes any >> case where the file is not included the module, whether or not the name you >> refer it by lexically contains . or '..'. >> >> Both phrases are necessary. >> >> On Sat, Jan 16, 2021 at 7:24 PM Axel Wagner <axel.wagner...@googlemail.com> >> wrote: >> >> Manlio Perillo <manlio.peri...@gmail.com>: Jan 16 12:02PM -0800 >> >> Thanks. I was only considering the parent of the module's root directory. >> Is the concept of "outside the module" defined somewhere? >> >> Manlio Perillo >> >> Il giorno sabato 16 gennaio 2021 alle 19:30:05 UTC+1 >> Manlio Perillo <manlio.peri...@gmail.com>: Jan 16 12:04PM -0800 >> >> As an example: is testdata outside the package's module? >> >> Thanks >> Manlio >> Il giorno sabato 16 gennaio 2021 alle 21:02:25 UTC+1 Manlio Perillo ha >> scritto: >> >> Axel Wagner <axel.wagner...@googlemail.com>: Jan 16 09:08PM +0100 >> >> I think this is the best doc about what is included in a module: >> https://golang.org/ref/mod#zip-path-size-constraints >> Everything not in that list is "outside" that module. >> >> On Sat, Jan 16, 2021 at 9:02 PM Manlio Perillo <manlio.peri...@gmail.com> >> wrote: >> >> Dmitri Shuralyov <dmits...@golang.org>: Jan 16 12:08PM -0800 >> >> Directories named testdata are included in the module; they're needed for >> tests to run. The most important thing that's left out are subdirectories >> that contain a go.mod file, since the content of such directories is a >> different module. >> >> Some good places to look for full details include >> https://golang.org/ref/mod#zip-path-size-constraints and >> https://pkg.go.dev/golang.org/x/mod/zip. >> >> On Saturday, January 16, 2021 at 3:04:58 PM UTC-5 manlio....@gmail.com >> wrote: >> >> Manlio Perillo <manlio.peri...@gmail.com>: Jan 16 12:23PM -0800 >> >> https://golang.org/ref/mod#zip-path-size-constraints prevents directories >> that begin with a dot, but only because the directory is interpreted as a >> package. >> It is not clear, to me, if `.git` is ignored by the `embed` directive >> because it is the private directory of the VCS or because it starts with a >> dot. >> >> >> Thanks >> Manlio Perillo >> Il giorno sabato 16 gennaio 2021 alle 21:09:08 UTC+1 >> Dmitri Shuralyov <dmits...@golang.org>: Jan 16 12:45PM -0800 >> >> It gets pretty subtle. The ".git" directories aren't included in module >> zips by the go command (I don't know if this is documented anywhere, but >> it's very sensible behavior), but they aren't disallowed. A custom module >> zip may include a ".foo", "_foo", or even ".git" directory with files. >> >> In the the phrase you mentioned: >> >> > Patterns must not match files outside the package's module, such as >> ‘.git/*’ or symbolic links >> >> Symbolic links are neither included not allowed. >> .git/* files aren't included by the go tool. >> >> As I understand, the "such as ‘.git/*’ or symbolic links" part is just an >> example of some common types of files that aren't included in modules. The >> important part of that phrase is "Patterns must not match files outside the >> package's module". For example, if you have this tree: >> >> $ tree . >> . >> ├── LICENSE >> ├── go.mod // module example.com/m1 >> ├── p.go >> ├── p_test.go >> └── nested >> ├── go.mod // example.com/m1/nested >> ├── foo.txt >> └── ... >> >> Then p.go can't embed "nested/foo.txt", because nested/foo.txt is going to >> be outside of the m1 module. >> >> If you're looking to improve package embed documentation, I suggest filing >> an issue <https://golang.org/issue/new>. If your goal to understand this >> better for your own interests, I hope you find the nuanced details above >> interesting. :) >> On Saturday, January 16, 2021 at 3:23:32 PM UTC-5 manlio....@gmail.com >> wrote: >> >> Axel Wagner <axel.wagner...@googlemail.com>: Jan 16 09:47PM +0100 >> >> In general, embedding files from directories starting with dot ("hidden >> directories") works fine. But you must take care, to either mention the >> hidden directory explicitly, or the file you want to exclude, as otherwise, >> the hidden directory will be skipped by embed (see >> https://github.com/golang/go/issues/42328). >> .git is thus special. As >> https://pkg.go.dev/golang.org/x/mod/zip#CreateFromDir mentions, .git and >> similar directories are skipped when creating the zip file of a module, >> because they are not deemed "part of the module" (which, I think, makes a >> lot of sense), so they can't be embedded based on the rule that embedded >> files must be part of the module (i.e. they must be included in the zip >> file). >> It might be reasonable to spell the skippage of .git etc. out more >> specifically in the docs. >> >> On Sat, Jan 16, 2021 at 9:24 PM Manlio Perillo <manlio.peri...@gmail.com> >> wrote: >> >> Back to top >> GODOC: how to create a reference to another definition in a comment? >> "atd...@gmail.com" <atd...@gmail.com>: Jan 16 05:20AM -0800 >> >> Hello, >> >> Just wondering if there is a way to create references to other fields in go >> comments. >> If it does not exist, wouldn't it be something valuable, for easier >> navigation in godoc and its new iteration? (I would assume that we would >> have to check comments for broken references on code change) >> Back to top >> `go list` across multiple modules? >> Tim Hockin <thoc...@google.com>: Jan 15 03:43PM -0800 >> >> > example.com/m/submod v0.0.0 => ./submod >> > ) >> >> > I think you might have tried this already. It gives the same "main module >> > ... does not contain package" error. I believe that's a bug. I've opened >> > #43733 to track it. >> >> Interesting. If that's a bug, then maybe I'll be able to do what I >> need once fixed. >> >> > In general, it should be possible to give 'go list' an absolute or >> > relative path (starting with ./ or ../) to any directory containing a >> > package which is part of any module in the build list. For example, some >> > tools list directories in the module cache to find out what package a .go >> > file belongs to. >> >> > As a workaround, you could put a go.mod in an otherwise empty directory >> > (in /tmp or something), then require the relevant modules from the repo >> > and replace them with absolute paths. Then you can run 'go list' in that >> > directory with absolute paths of package directories. >> >> Interesting - is the difference the absolute paths vs relative? >> >> I hoped maybe `-modfile` would do the same trick, but alas not: >> >> ``` >> $ (cd /tmp/gomodhack/; go list /tmp/go-list-modules/submod/used/) >> example.com/m/submod/used >> >> $ go list --modfile /tmp/gomodhack/go.mod /tmp/go-list-modules/submod/used/ >> main module (tmp) does not contain package tmp/submod/used >> ``` >> >> It also fails some cases: >> >> ``` >> (cd /tmp/gomodhack/; go list /tmp/go-list-modules/submod/used/) >> example.com/m/submod/used >> thockin@thockin-glaptop4 go-list-modules main /$ (cd /tmp/gomodhack/; >> go list /tmp/go-list-modules/staging/src/example.com/other1/used/) >> go: finding module for package >> example.com/m/staging/src/example.com/other1/used >> cannot find module providing package >> example.com/m/staging/src/example.com/other1/used: unrecognized import >> path "example.com/m/staging/src/example.com/other1/used": reading >> https://example.com/m/staging/src/example.com/other1/used?go-get=1: >> 404 Not Found >> ``` >> >> It seems that is because the "main" (top-level dir) go.mod has >> `replace` directives with relative paths, which kubernetes really >> does. >> >> > Incidentally, golang.org/x/tools/go/packages will call 'go list' under the >> > hood in module mode. go/build might do the same, depending on how it's >> > invoked. 'go list' may be the best thing to use if it gives the >> > information you need. >> >> Yeah, I noticed. When GO111MODULE=off, everything I am doing is much >> faster. I'm wary of depending on that forever, though. >> >> Stepping back, I fear I am pushing the square peg into a round hole. >> Let me restate what I am trying to do. >> >> I want to run a slow codegen process only if the packages it depends >> on have ACTUALLY changed (mtime is a good enough proxy) and I don't >> know a priori which packages need codegen. I want to scan the file >> tree, find the files that need codegen, check their deps, and only >> then run the codegen. >> >> We do this today with `go list` and GO111MODULE=off, but I was advised >> at some point that x/tools/go/packages was the future-safe approach. >> >> If there's a better way, I am all ears. >> >> Tim >> GO111MODULE=off >> Randall O'Reilly <rcoreil...@gmail.com>: Jan 16 12:45AM -0800 >> >> Is the slowness here related to https://github.com/golang/go/issues/29427 ? >> I'm not sure the earlier fix for that actually fixed the issues I was having >> (and the issue remains open) -- I need to do more research for my situation, >> but just in case this might be another reason to revisit the slowness factor >> there.. >> >> - Randy >> >> Back to top >> super large virtual memory allocation for simplest golang apps, why? >> "pat2...@gmail.com" <pat22...@gmail.com>: Jan 15 08:00PM -0800 >> >> > got 'can't fork: out of memory' if I set overcommit_memory to 2, change it >> > to 0 made this disappear. However for embedded systems I normally set >> > overcommit as 2 and no swap to avoid OOM in the field. >> >> The big footprint is from common libraries and runtime system. I believe >> this is a clear result of the design decision trying to avoid >> "DLL hell" that we all lived with in the early Windows era. >> >> If we all ran a good operating system, such as Tenex, most of the libraries >> would be shared by virtual page system. Automatically, >> so that even in a small real world memory system, it would be fine. The >> early Tenex systems typically had about 480 K of memory. Back in 1969, that >> was very expensive. Now that I think about it, the memory size and CPU >> speed of those early Tenex systems is far smaller than most embedded >> microcontrollers. See Tenex, by >> BBN. https://en.wikipedia.org/wiki/TENEX_(operating_system) >> Back to top >> [ANN] go-featureprocessing v1.0.0 >> Nikolay Dubina <nikolay.dubina....@gmail.com>: Jan 15 06:10PM -0800 >> >> *What is this?* >> >> Fast feature preprocessing in Go with feature parity to sklearn >> >> https://github.com/nikolaydubina/go-featureprocessing >> >> *What is new?* >> >> - Added batch processing >> - Added inplace processing >> - Added parallel processing >> - Made all inference code to have zero memory allocations >> - Added sklearn Python comparison benchmarks >> - Did a lot of benchmarking >> - Cleaned up API >> - Cleaned up generated code a bit >> - Made more realistic generated tests >> - Made more realistic benchmarks >> - Improved documentation >> >> Thanks! 🛠 >> >> - Nikolay >> Back to top >> Context on one-shot structs >> Ross Light <r...@zombiezen.com>: Jan 15 03:44PM -0800 >> >> The Go CDK stores a Context in a struct while performing I/O: >> https://pkg.go.dev/gocloud.dev/blob#Bucket.NewWriter >> >> It could be argued that this is done for compatibility with the io.Reader >> and io.Writer interfaces. However, I think this pattern, used sparingly, is >> suitable for API interactions where multiple method calls are required for >> a single conceptual task. >> >> -Ross >> >> On Tuesday, January 12, 2021 at 9:29:39 AM UTC-8 Jean de Klerk wrote: >> >> Back to top >> You received this digest because you're subscribed to updates for this >> group. You can change your settings on the group membership page. >> To unsubscribe from this group and stop receiving emails from it send an >> email to golang-nuts+unsubscr...@googlegroups.com. > > > > > > WARNING / LEGAL TEXT: This message is intended only for the use of the > individual or entity to which it is addressed and may contain information > which is privileged, confidential, proprietary, or exempt from disclosure > under applicable law. If you are not the intended recipient or the person > responsible for delivering the message to the intended recipient, you are > strictly prohibited from disclosing, distributing, copying, or in any way > using this message. If you have received this communication in error, please > notify the sender and destroy and delete any copies you may have received. > > http://www.bsc.es/disclaimer > > > > > > > WARNING / LEGAL TEXT: This message is intended only for the use of the > individual or entity to which it is addressed and may contain information > which is privileged, confidential, proprietary, or exempt from disclosure > under applicable law. If you are not the intended recipient or the person > responsible for delivering the message to the intended recipient, you are > strictly prohibited from disclosing, distributing, copying, or in any way > using this message. If you have received this communication in error, please > notify the sender and destroy and delete any copies you may have received. > > http://www.bsc.es/disclaimer > -- > You received this message because you are subscribed to the Google Groups > "golang-nuts" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to golang-nuts+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/golang-nuts/C0FFE87C-3710-48A8-B2FD-DDB16330FB70%40bsc.es. -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CBE59ED0-E87A-409C-99BC-358A75C93EEC%40ix.netcom.com.