Speaking of IO ...
In an imperative program you get guaranteed ordering of those instructions, but that ordering is thread local, meaning that the compiler, the runtime, the kernel, the CPU are all free to reorder instructions for optimal execution and ordering between threads is forced via memory barriers, which is in fact incredibly error prone.
In an FP language such as Haskell you get the extra problem that the compiler is even more free to rewrite and execute your code in any order it sees fit due to non-strictness and to referential transparency.
What the IO monad does is to "suspend side effects" and to force ordering on evaluation. And guess what, the IO monad is useful even in your average imperative program for describing concurrent logic.
Here are the implementations I contributed to:
1. https://monix.io/docs/2x/eval/task.html (Scala)
2. https://github.com/typelevel/cats-effect (Scala)
3. https://funfix.org (JavaScript)
If you've ever worked with JS Promises, think of IO as a non-broken, pure, awesome alternative.
And this is just IO. There are other monads as well. List is a monad, Option and Either are monads ;-)
---
I recommend you let go of your misconceptions and do some learning because this is a freaking useful concept.