By adding suspend modifier to a function, you allow the function to use another suspending functions. For example, if the runMe() function would use suspending delay it's reasonable to make that function suspendable. See Your first coroutine documentation section.
Another major difference of suspending functions over ordinary ones, is that the suspending functions are cancellable. Let's look at the Android example:
class MyViewModel : BaseViewModel() {
init {
viewModelScope.launch {
val firstPart = loadFirstPartOfData()
val secondPart = loadSecondPartOfData(firstPart)
...
}
}
suspend loadFirstPartOfData() = withContext(Dispatchers.IO) { ... }
suspend loadSecondPartOfData(firstPartOfData: FirstPartOfData) {
// some UI thread safe calculations
return withContext(Dispatchers.IO) {
// network request here
}
}
}
Imagine that the view (Android Activity) loads the data to display it. If the Activity is closed before the second part of data is loaded, it's wasteful to load the second part. But, because the loadSecondPartOfData() function is suspending, it checks whether the scope is active or not, and the function won't be executed if the scope isn't active.
Also notice how the functions use withContext(Dispatchers.IO). The functions are called from viewModelScope.launch, which by default uses Dispatchers.Main (UI thread), but it's safe to call the functions from UI thread because the execution context is explicitly selected by the functions. It's the right way to write suspending functions, when you don't worry about the current thread when you call a function. It's regarding your third question.
In your example, the first snippet will work, but in a real app, as usual, things become a little bit more complex.