IQueryable 异步扩展方法精确时间执行和返回任务

IQueryable async extension methods exact time execution and returned task

我有一个方法 returns 来自数据库的数据

public Task<List<T>> GetAsync(int someId)
    {
        return dbSet
            .Where(x => x.Id == someId)
            .ToListAsync();
    }

我有一个字典,通过某个键存储任务

Dictionary<int, Task<List<T>>> SomeDictionary { get; set; }

在其他地方我得到任务并将其放入字典

var someTask = repo.GetAsync(someId);
someInstance.AddInDictionary(key, someTask);

然后我得到任务并等待它得到结果

var task = someInstance.GetFromDictionary(key);
List<T> result = await task;

所以我的问题是: 1. IQueryable 翻译成sql 在数据库哪里查询执行: 当我在 repo

中调用方法时
var someTask = repo.GetAsync(someId); 

-或者当我等待任务时

List<T> result = await task;

2。在字典中,当我存储 Tasks

Dictionary<int, Task<List<T>>> SomeDictionary { get; set; }

...我是只存储应该 return 结果的操作,还是与实际结果一起存储的操作?换句话说,保存Task而不是保存List,是否节省内存?

提前致谢。

await 关键字是有效的语法糖。它以与回调相似(不相同)的方式工作,其中回调是执行 await 的代码。它不控制 Task 何时或如何执行。

这意味着Entity Framework在不知道await的情况下负责调度和执行Task,因此有能力调度Task的执行随心所欲。

根据 ToListAsync 的实现方式,它可能包含一部分与当前线程同步执行的代码。

我没有看到 Microsoft 声明 什么时候 IQueryable 被翻译成 SQL,或者与 SQL 服务器的连接是发起。我的猜测是 IQueryable 被转换为 SQL 并且连接握手在调用 ToListAsync 后立即开始,并且该方法的其余部分尽快在其中一个上执行ThreadPool 个线程。

也就是说,调用代码的编写方式应该不依赖于异步方法的内部操作。

至于你问题的第二部分,Task是引用类型。它与任何其他引用类型具有相同的 memory overhead。如果您声明 N 字段以容纳 N Tasks,您最终会得到 N * B bits,其中 B 是 3264,具体取决于你的操作系统。如果将它们存储在 List 中,这也是一个引用类型,您最终可能会消耗更多内存,因为 List 内部保留了一个比需要的更大的数组,因此它可以 append/prepend 项目更有效率。如果您将 N Tasks 存储在 ArrayN 元素中,您最终会得到 (N + 1) * B (可能更多,不确定),因为数组也是一个引用。