This question explores the unexpected performance degradation when introducing concurrency to an existing Go program. The code simulates interactions with monsters in a game, keeping track of successful item drops. To improve efficiency, the programmer tried splitting the workload among available processors using concurrency, but it resulted in a significant slowdown.
Without concurrency, the program runs a series of simulations (1000 in this case), and each simulation runs a specified number of interactions (1,000,000 in this example). The results are then used to compute the total number of successful interactions.
To parallelize the code, the programmer creates multiple goroutines, each responsible for running a portion of the simulations. They correctly divide the workload among the available CPUs, matching the number of goroutines to the number of processors.
Surprisingly, instead of improving performance, the concurrent code ran 4-6 times slower than its sequential counterpart.
The issue lies in the shared state being accessed by concurrent goroutines. Specifically, the rand.Float64() function uses a shared global Rand instance with an associated mutex lock. When multiple goroutines attempt to access the global Rand instance, they must acquire the mutex lock, leading to contention and slowing down the code.
To resolve the performance issue, the programmer creates a separate Rand instance for each goroutine. This eliminates the contention for the global Rand instance, allowing goroutines to run independently.
Creating a separate Rand instance for each goroutine significantly improves performance. The concurrent code now runs about 2.5 times faster than the non-concurrent version on a dual-core CPU.
This scenario demonstrates the importance of understanding the synchronization mechanisms used by shared resources when implementing concurrency. It underscores the impact of data access patterns on performance and the need to consider the trade-off between processor utilization and synchronization overhead.
The above is the detailed content of Why is My Concurrent Go Code Slower Than Its Sequential Counterpart?. For more information, please follow other related articles on the PHP Chinese website!