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

时间:2018-03-29 22:21:40

标签: c# entity-framework asynchronous task iqueryable

我有一个从数据库中返回数据的方法

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

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

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

在其他地方,我得到了Task并把它放在字典中

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

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

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

所以我的问题是: 1. IQueryable在哪里转换为sql查询并在数据库中执行:    当我在回购中调用方法时

var someTask = repo.GetAsync(someId); 

- 当我等待任务时

List<T> result = await task;

2。在字典中,当我存储任务

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

...我只存储应该返回结果的操作,还是存储与实际结果一起的操作?换句话说,保存任务而不是保存列表,保存任何内存吗?

提前致谢。

1 个答案:

答案 0 :(得分:2)

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

这意味着实体框架负责在不知道Task的情况下安排和执行await,因此能够根据需要安排Task的执行。< / p>

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

IQueryable转换为SQL,或者启动了与SQL Server的连接时,我没有看到Microsoft状态。我的猜测是IQueryable被转换为SQL并且在调用ToListAsync时立即开始连接握手,并且在{{1}之一上尽快执行该方法的其余部分}线程。

话虽这么说,调用代码应该以不依赖于异步方法的内部操作的方式编写。

至于问题的第二部分,ThreadPool是引用类型。它与任何其他引用类型具有相同的memory overhead。如果您声明Task字段要容纳N N,那么您最终会得到Tasks,其中B为N * B bits32,具体取决于你的操作系统。如果将它们存储在64中,这也是一种引用类型,您可能最终会占用更多内存,因为List内部保留的数组比必要的大,因此它可以附加/预置项目更有效率。如果您将List N存储在Tasks Array个元素中,那么您最终会得到N(可能会更多,不确定),因为数组也是一个参考。