Hone logo
Hone
Problems

Concurrent Task Execution with a Goroutine Pool

Building a goroutine pool is a common pattern in Go for managing concurrent tasks efficiently. This challenge asks you to implement a simple goroutine pool that limits the number of concurrently running goroutines, preventing resource exhaustion and improving performance in scenarios with many short-lived tasks. A well-designed goroutine pool allows you to control concurrency and avoid overwhelming the system.

Problem Description

You are tasked with creating a GoroutinePool type in Go that manages a fixed-size pool of goroutines. The pool should accept tasks (represented as functions with no arguments and no return values) and execute them concurrently, respecting the pool's size limit.

What needs to be achieved:

  • Implement a GoroutinePool struct with a size field representing the maximum number of concurrent goroutines.
  • Implement a Submit method that accepts a task (a function with signature func()) and queues it for execution.
  • The Submit method should block if the pool is currently at its maximum capacity, waiting for a goroutine to become available.
  • The pool should handle tasks gracefully, ensuring that all submitted tasks are eventually executed.
  • The pool should be safe for concurrent use by multiple goroutines submitting tasks.

Key Requirements:

  • Fixed Size: The pool's size is determined at creation and remains constant.
  • Concurrency Control: The pool limits the number of concurrently running goroutines to the specified size.
  • Task Queue: Tasks are queued when the pool is full and executed as goroutines become available.
  • Blocking Submit: The Submit method blocks when the pool is full.
  • Thread Safety: The pool's internal state (task queue, running goroutine count) must be protected against race conditions.

Expected Behavior:

When a task is submitted to the pool:

  1. If the pool has available goroutines, a new goroutine is launched to execute the task immediately.
  2. If the pool is at its maximum capacity, the Submit method blocks until a goroutine finishes and becomes available.
  3. Once a goroutine becomes available, the next task in the queue is executed.

Edge Cases to Consider:

  • Empty Task Queue: What happens when the task queue is empty and all goroutines have finished? The pool should remain idle, ready to accept new tasks.
  • Panic Handling: Consider how to handle panics within the submitted tasks. Ideally, the pool should not crash due to a panic in a worker goroutine. (While not strictly required for a basic implementation, it's a good consideration for robustness).
  • Pool Size of 0: What should happen if the pool is initialized with a size of 0? It should likely block indefinitely on Submit.

Examples

Example 1:

Input: Pool size = 2, Tasks: [func() { print("Task 1") }, func() { print("Task 2") }, func() { print("Task 3") }]
Output: (Order may vary, but all tasks will eventually print)
Task 1
Task 2
Task 3
Explanation: Two goroutines will run concurrently, executing Task 1 and Task 2.  Once one of them finishes, Task 3 will be executed.

Example 2:

Input: Pool size = 1, Tasks: [func() { print("Task 1") }, func() { print("Task 2") }, func() { print("Task 3") }]
Output: (Order may vary, but all tasks will eventually print)
Task 1
Task 2
Task 3
Explanation: Only one goroutine will run at a time. Task 1 will run, then Task 2, then Task 3.  The Submit calls for Task 2 and Task 3 will block until Task 1 completes.

Example 3: (Edge Case)

Input: Pool size = 0, Tasks: [func() { print("Task 1") }]
Output: (Submit blocks indefinitely)
Explanation:  The pool is initialized with a size of 0, so no goroutines can ever run. The Submit call will block forever.

Constraints

  • The pool size must be a positive integer.
  • Tasks are functions with no arguments and no return values (signature func()).
  • The Submit method should block if the pool is full.
  • The implementation must be thread-safe.
  • The pool should not leak goroutines.

Notes

  • Consider using a channel to manage the task queue.
  • A sync.WaitGroup can be helpful for tracking the number of active goroutines.
  • Think about how to signal the pool to shut down gracefully (this is not required for the basic implementation, but it's a good consideration for a more complete pool).
  • Focus on correctness and thread safety first. Performance optimizations can be considered later.
Loading editor...
go