|
|
|
|
|
by simiones
2222 days ago
|
|
Hmm, I think it only looks magical because I chose a relatively unfair comparison, I realize now. To show a more realistic comparison, let's asume Bar() is not "async ready" in either Go or C#. Then, the C# code would look something like this: async Task<int> Foo() {
var task = Task.Run(() => Bar());
int i = await task;
return i + 1;
}
This compares more clearly to the Go version with the same assumption: func Foo(ret chan int) {
task := make(chan int, 1)
go func() {
task <- Bar()
}
i := <-task
ret <- i + 1
}
So the readability / cleanliness is pretty similar for simple examples. However, once you start doing more complex things, like I showed in my second example, the difference become much more pronounced. Overall, a `Task<T>` offers much more information to callers than a `chan T`, so it can usually be composed in more interesting ways, but it can also sometimes be more cumbersome to use.And again, in both languages, there are clear demarcations between async functions and blocking functions. In C#, async functions return `Task<T>` and are usually marked `async`, while in Go async functions have one or more `chan T` arguments and don't normally return values. If you want to call an async function from a non-async function or vice-versa, you need to use special constructs (e.g. Task.Run, Task.Wait or Task.Result for C#, and `go func () {...}` and blocking channel reads/writes in Go). |
|