异步等待执行流程的差异

时间:2019-11-20 12:59:55

标签: c# .net asynchronous async-await task

使用以下两种方法,自上而下的流程(其中top是API动作,down是Db事务)之间有什么区别。

完整的异步等待流程

async Task X()
{
   await Y();
}

async Task Y()
{
    await Z();
}

async Task Z()
{
    await session.CommitAsync();
}

仅顶级方法使用async-await。

async Task X()
{
   await Y();
}

Task Y()
{
    Z();

    return Task.CompletedTask;
}

Task Z()
{
    session.CommitAsync();

    return Task.CompletedTask;
}

当异步指示Y应该异步执行时,Z发生了什么?

2 个答案:

答案 0 :(得分:2)

  

异步指示Y应该异步执行,

是错误的陈述。异步修饰符允许 Y等待某些事情,它不会强制执行任何异步操作。

只要something()实际上正在执行异步操作,您的第一个代码段就可以了。

第二个根本不是异步的,它只是抛出一些asyncawait关键字,但是在这里并没有完成任何事情。

答案 1 :(得分:1)

编辑:问题已更改。以下是一般的异步答案

后面的Z根本不会等待CommitAsync才返回。这是一种失火的情况。

Task Z()
{
    session.CommitAsync();

    return Task.CompletedTask;
}

在api控制器的情况下,这意味着Web请求将在提交会话之前返回给客户端。

请注意,对于返回数据的方法,无法完成此操作。

第二个注意事项是,返回Task并没有任何好处,返回类型可以更改为void(这可能会或可能不会帮助您进行推理)。

原始答案,仍然有用

假设在ZRealAsync中调用await db.(...).ToListAsync(),在ZPretendAsync中调用ToList(),然后返回Task.CompletedTask

区别在于,将查询发送到数据库后,恰好调用ZRealAsync的线程可用于执行其他操作,而调用ZPretendAsync的线程将无法执行。用于其他任何事情,直到从数据库中获得结果,它都将等待;即使X被标记为async并使用await

如果您的网络控制器调用ZPretendAsync,则即使X被标记为async并使用{ {1}}关键字。使用await,n个线程可以处理n个以上的并发请求。 ZRealAsync会带来真正的改变,但前提是它是真实的。