Executing say_after (without await) creates a coroutine object, but does not start it yet.
If you await on the coroutine object, then you are executing the coroutine until the Python encounters one of await or return (or end of function) in the coroutine. "Executing" here means transforming the coroutine into a Task object and put that object in the async loop.
However, create_task immediately 'starts' the coroutine and put them tasks in the async loop (though, because this is async instead of parallel, execution does not actually begin until Python encounters await in main()).
In your situation, as soon as Python sees the await task1, it 'leaves' main() and loops among task1 and task2 back and forth (because both tasks have been put in the async loop by create_task) until task1 is completed (because task1 is the one being await-ed on). Because task2 had scheduled itself to wait for a shorter time, it finishes first. About 1 second later, task1 completes, and only then execution returns to main() (because, remember, it was task1 that main() had been await-ing on).
At this point, both task1 and task2 has completed; the await task2 line practically does nothing; it's just "wrapping up" task2 and (almost) immediately returns.