Blocking and non-blocking aren’t really about performance, they are about an interface.
If you have a single thread of execution then a blocking call prevents your program from doing any useful work while it’s waiting.
But if you have multiple threads of execution a blocking call doesn’t really matter because you can just leave that thread blocked and do useful work in another.
In Go, a goroutine is swapped out for another one when it blocks on I/O. The Go runtime uses non-blocking I/O syscalls to avoid the operating system blocking the thread so a different goroutine can be run on it while the first is waiting for it’s I/O.
Goroutines are really cheap so writing non-blocking style code is not needed.