Use delay with a fixed total time to defend against timing attacks

Consider this common example used to demonstrate timing attacks:

async def sign_in(username, password):   user = await get_user_from_db(username)   if user is None:     return False  # early return :(    password_hash = slow_hash(password)   return verify(password_hash, user.password_hash) 

The usual suggestion is to do the same thing on all execution branches. For example, something like this:

async def sign_in(username, password):   user = await get_user_from_db(username)   if user is None:     actual_password_hash = "foo"   else:     actual_password_hash = user.password_hash    password_hash = slow_hash(password)   res = verify(password_hash, actual_password_hash)   return res and user is not None 

But I wonder if the following strategy is also useful against timing attacks (not considering other types of side-channel attacks), while not wasting computing resources:

async def sign_in(username, password):   # Longer than what `sign_in_impl` takes normally   fixed_duration = ...     _, sign_in_result = await asyncio.gather(delay(fixed_duration), sign_in_impl)    return sign_in_result  # Awaits a certain amount of time async def delay(duration):   ...  # This takes variable time async def sign_in_impl(username, password):   user = await get_user_from_db(username)   if user is None:     return False  # early return :(    password_hash = slow_hash(password)   return verify(password_hash, user.password_hash)