运行 使用 Task.Run() 的同步方法是否使其异步

Does running a synchronous method using Task.Run() make it asynchronous

让我们考虑一个 class(这不是我在我的应用程序中使用的 class 或代码,只是想通过这个例子来学习)

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

现在假设我从我的数据库中获得了上述 class 的对象列表。如果体积很大,我会想要一个部门 ID 和部门名称的字典。 Dictionary.

形式的东西

我在class里面有一个方法如下:

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;
}

我的 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);
    }
}

我的问题是:

  1. 这是我编写的用于从我的列表中创建字典的方法,它 运行 是异步的吗?
  1. 这与将我的字典逻辑放在异步方法中有什么区别?
  2. 无论我实现了什么,这是否有点类似于拥有 .ToDictionaryAsync() 方法?

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

可能更准确地说运行s 并列。创建一个单独的线程来产生结果。如果 people 没有以 thread-safe 的方式使用(例如,它是您要添加到其他线程中的列表),那么您最终可能会遇到混乱的竞争条件。

当人们谈论“异步”代码时,他们可能指的是两件事。

  1. 以不阻塞线程的方式模拟固有异步操作的代码,如磁盘或网络 I/O。
  2. 更广泛地说,可以独立于当前操作线程完成的任何类型的操作。

您所做的符合第二个定义,但不符合第一个。如果 people 由数据库 round-trip 支持,您的代码在该调用完成时仍会阻塞一个线程:它只会阻塞与调用 MapDepartments.[= 的线程不同的线程。 26=]

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

由于您是从 in-memory 列表中提取数据,并且您的所有操作都是 CPU-bound(不是真正的异步操作),因此将您的逻辑放在 async 方法,因为该方法对 await 没有任何意义。即使该方法会说它是 async,它也会 运行 同步 在返回任务之前完成。

假设创建该字典确实需要足够的时间使其变得有价值 multi-threading,并且假设您在 await 任务之前没有修改基础列表,那么您当前的方法更好。

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

我的意思是,我猜你可以写一个 ToDictionaryAsync 方法,它只在一个单独的线程上执行 ToDictionary,但这确实不符合 Async 的精神。

当像 Entity Framework 这样的库提供 ToDictionaryAsync() 方法时,那是因为他们知道将有一个实际的数据库调用实际上是异步的,并且他们知道如何在non-blocking 方式而不调用 ToDictionary()。对于这种情况,我会保留 ToDictionaryAsync