It's something that I'm both surprised and not all that surprised it hasn't made its way into more async/await languages exactly because of that confusing complexity.
I believe that in Python, due to its explicit over implicit philosophy, you could almost fake SynchronizationContext/Scheduler dynamics with a smart enough "event loop" as your outermost async runner, monkey patching coroutine return Futures/Tasks to include CurrentSynchronizationContext/CurrentScheduler information. It even looks like at a shallow skim some of that is designed into the default asyncio event loop system in the form of "custom event loop policies", but in the same skim it seems like its both more complex in its own way than SynchronizationContext/Scheduler (such as its primary job seems to be in handling platform specifics), and cursory searches don't show anyone attempting to use it for backpressure management.
Not that in most cases I would write backpressure management code directly in SynchronizationContext/Scheduler "magic" today: I'd use ReactiveX glue and explicitly define Schedulers there and/or make use of "off-the-shelf" RX backpressure combinators. But the low level capability at the .NET SynchronizationContext/Scheduler level is an often overlooked "magic" to async/await that can get results from existing async/await code without needing to rewrite existing async/await code. (I think the fact that RX.NET itself can piggy back off of that low level most directly as opposed to in other languages/environments implementing its scheduler support and backpressure work with less low level underlying support is also easy to overlook that .NET seems to be doing it all more cohesively under the hood.)