no, vs blocking the UI thread. Which is perfectly fine the vast majority of the cases, unless you are running something long running.
You are trying to something slightly complex. I don't see how one could make it any easier from a language design perspective and staying idiomatic to the language.
Go: Goroutines make you wire the "stop" scenario on your own (channel close). Rust: Hold on to your future and drop() it. C#: Pass a cancellation token and call Cancel()
All seem reasonable and stay within what they think their developers will be able to pick up and run with.
In my experience, the complexity is vastly reduced by not having to implement tricky asynchronous APIs (Task Paralell, thread pools, BackgroundWorker, etc).