exercism / go

Exercism exercises in Go.
https://exercism.org/tracks/go
MIT License
973 stars 649 forks source link

Adding concurrency concepts to the syllabus #2645

Open junedev opened 1 year ago

junedev commented 1 year ago

This is a placeholder issue for the work on concurrency related concepts and learning exercises.

Overview

This will be the first bit for teaching concurrency in the syllabus. Overall, we want to add the following concepts:

Later we could add more things:

Besides that, we also already have some unfinished work regarding net/http in store.

Important Docs

If you have not yet contributed to concept exercises before, the followig upfront reading is required to acquire the necessary background knowledge.

Here you can read about what Concept Exercises are and how they are structured:

Also, be aware of these general guidelines:

sudomateo commented 1 year ago

Hey @junedev! I'd like to start work on this.

Specifically this item:

  • goroutines and waitgroups (two concepts in one exercise to allow for easier testing)

Learning Objectives

Here's the learning objectives that I think would be beneficial for students to know.

Goroutines

Wait Groups

Exercise

This exercise is called "Task Runner". The student must program a function that concurrently executes a slice of functions provided by the caller, using a WaitGroup to ensure all of the goroutines have successfully finished executing.

The API for this function looks like this.

func TaskRunner(workFn ...func()) {}

The testing code will call this function, passing in various worker functions that sleep for a period of time. The implementation will have to execute these functions concurrently otherwise the test will timeout and fail. For example, if we pass in three worker functions that take 100, 200, and 300 milliseconds respectively, then the implementation should take no longer than 300 milliseconds to return +/- a few percent to account for scheduling and time variations. The test will use a context with a timeout to track this execution.

Here's example code for how the test will call the student's implementation.

func TestTaskRunner(t *testing.T) {
    ctx, cancel := context.WithTimeout(context.Background(), 310*time.Millisecond)
    defer cancel()

    done := make(chan struct{})

    go func() {
        TaskRunner(
            func() { time.Sleep(100 * time.Millisecond) },
            func() { time.Sleep(200 * time.Millisecond) },
                        func() { time.Sleep(300 * time.Millisecond) },
        )

        done <- struct{}{}
    }()

    select {
    case <-done:
        // Success case. Do nothing on purpose.
    case <-ctx.Done():
        t.Fatal("Took too long! Failed!")
    }
}

Let me know what you think of these learning objectives and exercise and, once we finalize them, I can get to work on this.

junedev commented 1 year ago

Thanks for the proposal, looks good so far, some additional thoughts that came to mind...

Re the learning objectives for Goroutines:

Re waitgroups:

Re the concepts in general:

Re the exercise:

junedev commented 1 year ago

Sidenote: For the concurrency exercises it probably makes sense to activate the race detector for the automated test runs that Exercism does, you can read how to do that here https://github.com/exercism/go-test-runner#providing-additional-testing-flags .