Giter Club home page Giter Club logo

Comments (1)

alitto avatar alitto commented on May 30, 2024

Hey @koenbok!

I'm afraid nested groups will not work with that setup, since it's reusing the same worker pool for both group levels (A and B). Each worker pool receives submitted tasks via a single channel and these are grabbed by worker goroutines in a FIFO manner.
To visualize it more clearly, this is one of the many possible scenarios of how tasks end up queued in the worker pool's channel. Notice that each task of the group A will be running in a different goroutine (outside the main one), so there's no guarantee about it running before the next iteration of the for loop that creates A tasks.

// 1. Initial state, empty task queue
[]

// 2. Group A task submitted
[ A1 ]

// 3. Group A task submitted
[ A1, A2 ]

// 4. Group A task submitted
[ A1, A2, A3 ]

// 5. Group B1 task submitted
[ A1, A2, A3, B11 ]

// 6. Group B1 task submitted
[ A1, A2, A3, B11, B12, .... ]

To simplify this exercise, lets assume the max number of workers in the pool is 2, although the same thing can happen with larger pool sizes.
Given that each task of group A waits until all its nested B tasks complete (groupB.Wait()), every time a worker goroutine grabs a task of group A, it will block until all its nested B tasks complete. Since we only have 2 workers and given that each worker grabs tasks from the queue in order (FIFO), each one will grab an A task (A1 and A2). Therefore, once these 2 workers submit all their nested B tasks, they will both block. When all workers are blocked (2 in this case), the next tasks in the queue will not be processed because there is no idle worker to grab them.

Possible workaround

One possible workaround would be to have a dedicated worker pool for each task level (A vs B). It would look something like this:

poolA := pond.New(16, 1_000_000)
poolB := pond.New(16, 1_000_000) // You can tweak these parameters as needed

groupA := poolA.Group()

for i := 0; i < 100; i++ {
	groupA.Submit(func() {
		fmt.Println("A", i)
		groupB := poolB.Group()
		for i := 0; i < 10; i++ {
			groupB.Submit(func() {
				fmt.Println("B", i)
			})
		}
		groupB.Wait()
	})
}

groupA.Wait()

Given that each pool will have its own FIFO queue, there shouldn't be any deadlock here 🙂

I hope you find this helpful and please feel free to submit pull requests with improvements to the docs if you want, that would be really appreciated 🙏 and it could help others that came across this use case.

from pond.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.