0

I have a method that returns data from the database

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

I have a dictionary that stores Task by some key

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

In some other place I get the Task and put it in the dictionary

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

Then I get the task and await it to get the result

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

So my questions are: 1. Where do the IQueryable translate to sql query and execute in the database: when I call the method in the repo

var someTask = repo.GetAsync(someId); 

-or when I await the task

List<T> result = await task;

2. In the dictionary, when I store Tasks

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

...do I store only a operation that should return a result, or a operation together with the actual result? In other words, does saving the Task instead of saving the List, save any memory?

Thanks in advance.

M Bakardzhiev
  • 632
  • 5
  • 13

1 Answers1

3

The await keyword is effectively syntactic sugar. It works in a similar (not same) fashion to a callback, where the callback is the code proceeding the await. It does not control when or how the Task is executed.

This means that Entity Framework is responsible for scheduling and executing the Task without knowledge of await, and therefore has the ability to schedule the Task's execution however it desires.

Depending on how ToListAsync is implemented, it may contain a portion of code which executes immediately and synchronously with the current thread.

I have not seen Microsoft state when the IQueryable is translated in to SQL, or the connection to the SQL server is initiated. My guess would be that the IQueryable is translated to SQL and the connection handshake starts immediately upon calling ToListAsync, and that the remainder of the method is executed as soon as possible on one of the ThreadPool threads.

That being said, calling code should be written in such a way that it does not rely on the internal operations of the asynchronous method.

As for the second part of your question, Task is a reference type. It has the same memory overhead as any other reference type. If you declare N fields to house N Tasks, you'll end up with N * B bits, where B is 32 or 64 depending on your operating system. If you store them in a List, which is also a reference type, you'll probably end up consuming more memory, because List internally keeps a larger array than is necessary so it can append/prepend items more efficiently. If you store N Tasks in an Array of N elements, you'll end up with (N + 1) * B (could be more, not sure), since the array is also a reference.

cwharris
  • 17,835
  • 4
  • 44
  • 64
  • 1
    Thanks for answer. I wanted to know because it is related to my second question (and also with a dose of curiousity). – M Bakardzhiev Mar 29 '18 at 23:12
  • Edited for the second part of your question. :D – cwharris Mar 29 '18 at 23:16
  • I have just seen the edit...so an IEnumerable stores the pointers to the objects rather than the objects? – M Bakardzhiev Mar 29 '18 at 23:26
  • `IEnumerable` is an interface. It does not store anything (though the CLR does keep it's Type definition in memory). `List` and `Array` both implement `IEnumerable`, but `IEnumerable` has nothing to do with the *storage* of the items but rather how those items can be accessed. – cwharris Mar 29 '18 at 23:29
  • You are right, I meant IEnumerable implementations. – M Bakardzhiev Mar 29 '18 at 23:29
  • Value types are stored in the places they are declared. A `byte` field will reserve a byte of memory for every instance of the class/struct on which the field exists. An `object` field is going to reserve 32 or 64 bits of memory for every instance of the class/struct on which that field exists. The memory reserved for the *instance* of the object is elsewhere on the heap, and the `object` field simply points to it. – cwharris Mar 29 '18 at 23:39
  • https://stackoverflow.com/questions/5057267/what-is-the-difference-between-a-reference-type-and-value-type-in-c – cwharris Mar 29 '18 at 23:41