As of C# 7.0 async methods can return ValueTask
A more recent info from Marc (Aug 2019)
Use Task when something is usually or always going to be genuinely asynchronous, i.e. not immediately complete; use ValueTask when something is usually or always going to be synchronous, i.e. the value will be known inline; also use ValueTask in a polymorphic scenario (virtual, interface) where you can't know the answer.
Source: https://blog.marcgravell.com/2019/08/prefer-valuetask-to-task-always-and.html
I followed above blog post for a recent project when I had similar questions.