Goroutines and Dotnet Core Task Api Comparison

I was playing around today, and decided to compare golang goroutines with dotnet core Task API. I wrote the following code

var n = 1000000;
var tasks = new Task[n];
var sw = Stopwatch.StartNew();
for (var i = 0; i < n; i++ ) {
	tasks[i] = Task.Run(async() =>
		await Task.Delay(TimeSpan.FromSeconds(1)));
}
Task.WaitAll(tasks);
sw.Stop();
Console.WriteLine(sw.Elapsed.TotalSeconds);

Which ran on my machine in 45 seconds.

var t = time.Now()
var wg sync.WaitGroup
n := 1000000
wg.Add(n)
for i := 0; i < n; i++ {
	go func(){time.Sleep(1 * time.Second); wg.Done()}()
}
wg.Wait()
fmt.Println(time.Since(t))

and this ran in only 7 seconds.

Significant differance. This is probably due to two main reasons: the C# code allocates many tasks in memory in order for this to run, while the go code does not. Allocating memory causes some time delay. The second is that goroutine switching is more lightweight that switching running tasks in C#.

I am sure there is a more efficient way to write the C# code, but this is not a realistic example, and usning the task API is the canonical method of running threads in C#.