Home > Software design >  Does running a synchronous method using Task.Run() make it asynchronous
Does running a synchronous method using Task.Run() make it asynchronous

Time:05-24

Let's consider a class (This is not the class or code I'm using in my application, just trying to learn with this example)

class Person
{
    public int Id {get; set;}
    public string Name {get; set;}
    public int DeptId {get; set;}
    public string Department {get; set;}
}

Now let's assume I get a List of objects of the above class from my database. And if the volume is large, I would want a dictionary of Department Ids and the name of the department. Something in the form of a Dictionary<int,string>.

I have a method within the class as follows:

class Processing
{
        private Task<Dictionary<int,string>> MapDepartments(List<Person> people) => Task.Run(()=> people.GroupBy(p=>p.DeptId).ToDictionary(group=> group.Key, group=>group.First().Department;
}

And a separate method in my class

class Processing
{
    .
    .
    .
    Task DoStuff()
    {
        .
        .
        .
        //code execution to get data from the db
        var departmentDictTask = MapDepartments(people);
        .
        .
        .//some other code being executed, I don't need the department dictionary yet
        .
        .
        var dictionaryData = await departmentDictTask.ConfigureAwait(false);
    }
}

My questions are:

  1. Here the method I've written to create a dictionary out of my List, does it run asynchronously?
  • I'm thinking it does, because while debugging, I saw that it was in "Running" state for some time while my other code was running. Although I am not certain about whether this is indeed the case or not.
  1. What's the difference between this and putting my dictionary logic in an asynchronous method?
  2. Whatever I've implemented is this somewhat similar to having a .ToDictionaryAsync() method?

CodePudding user response:

Here the method I've written to create a dictionary out of my List, does it run asynchronously?

It's probably more accurate to say it runs in parallel. A separate thread is created to produce the result. If people isn't being used in a thread-safe way (e.g. it's a List that you're adding to in other threads), then you could end up with messy race conditions.

When people talk about "Asynchronous" code, there are two things they could mean.

  1. Code that models an inherently asynchronous operation, like Disk or Network I/O, in a way that doesn't block a thread.
  2. More broadly, any kind of operation that can complete independently from the current thread of operations.

What you've done matches the second definition, but not the first. If people were backed by a database round-trip, your code would still block a thread while that call completed: it would just be blocking a different thread than the one that calls MapDepartments.

What's the difference between this and putting my dictionary logic in an asynchronous method?

Since you're pulling from an in-memory List, and all your operations are CPU-bound (not doing truly asynchronous operations), there would be no benefit to putting your logic in an async method, because there would be nothing for that method to await. Even though the method would say it's async, it would run synchronously to completion before returning a Task.

Assuming creating that dictionary really takes enough time to make it worth multi-threading, and assuming you're not modifying the underlying list before you await the Task, your current approach is better.

Whatever I've implemented is this somewhat similar to having a .ToDictionaryAsync() method?

I mean, I guess you could write a ToDictionaryAsync method that just performs ToDictionary on a separate thread, but that's really not following the spirit of what Async means.

When a library like Entity Framework provides a ToDictionaryAsync() method, that's because they know there's going to be an actual database call that will actually be asynchronous, and they know how to make that happen in a non-blocking way without calling ToDictionary(). I would reserve ToDictionaryAsync for situations like that.

  • Related