mercredi 3 février 2021

How to test singleton with multiple goroutines?

I've implemented singleton pattern using the code below:

// Singleton definition.
type Singleton struct {
    Name string
}

var (
    instance *Singleton
)

// NewSingleton return singleton instance.
func NewSingleton() *Singleton {
    if instance == nil {
        instance = &Singleton{Name: "singleton"}
    }
    return instance
}

I knew that it's not the proper way to do that because multiple goroutines maybe return the different instances.

And now I just want to prove that using go test.

func TestParallelSingleton(t *testing.T) {
    count := 10
    instances := make([]*Singleton, count)
    signal := make(chan struct{})
    // New singletons with multiple goroutines.
    for i := 0; i < count; i++ {
        go func(c int) {
            instances[c] = NewSingleton()
            signal <- struct{}{}
        }(i)
    }
    // Wait for all goroutines to complete.
    for i := 0; i < count; i++ {
        <-signal
    }
    // Check all the singletons are equal.
    for i := 1; i < count; i++ {
        // t.Log(instances[i].Name)
        if instances[i] != instances[i-1] {
            t.Fatalf("Singleton instances %d and %d are not equal", i-1, i)
        }
    }
    t.Log("All singleton instances are equal")
}

func TestParallelSingleton1(t *testing.T) {
    count := 10
    instances := make([]*Singleton, count)
    for i := 0; i < count; i++ {
        i := i
        t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
            t.Parallel()
            instances[i] = NewSingleton()
            t.Logf("%p, %v", instances[i], instances[i])
        })
    }
}

But the result show that all the goroutines return the same instance with the same address which is strange.

I also increase the goroutines to 10,000 but the results are the same.

So is there something wrong with my code and what should I do?

Thanks in advance.

Aucun commentaire:

Enregistrer un commentaire