C# 了解阻塞 UI 和异步/等待与 Task.Run 的麻烦?

标签 c# asynchronous async-await task

我正在尝试执行一些与 UI 线程分离的异步 I/O 工作。我在某处读到:

  • 1) 对于受 CPU 限制的代码,您等待一个在 使用 Task.Run 方法的后台线程。比如计算质数 数字
  • 2) 对于 I/O 绑定(bind)代码,您等待返回一个操作 异步方法中的任务或任务。比如等待 网络或数据库

所以我这样做了:

// in windows form UI
private async void btnImport_Click(object sender, EventArgs e) {
    // [...]
    List<DataRow> rows = await importer.ImportDataAsync(123, 456);
    // [...]
}

// in Importer.ImportDataAsync:
public async Task<List<DataRow>> ImportDataAsync(int parent, int child, CancellationToken token = default(CancellationToken)) {

    // [...]
    List<DataRow> list = await RealImportFromDB(parent, child);
    return list;
    // [...]
}


public List<DataRow> RealImportFromDB(int p, int c) {

    List<DataRow> rowList;
    // here fetch the rows from DB over slow network
    // and return the row list
    return rowList;
}

通过这种方法,UI 被阻止了。 如果我这样调用 RealImportFromDB(...)

List<DataRow> l = await Task.Run(() => RealImportFromDB(parent, child));

UI 未被阻止,但与恕我直言上面的第 2 点冲突。

我哪里做错了?

最好的问候,亚历克斯

最佳答案

public List<DataRow> RealImportFromDB(int p, int c)是对数据库的阻塞调用,因此要异步执行它,您使用了 #1,您已将调用包装在 Task.Run 中,这将按预期释放 Ui 线程

With this approach the UI is blocked. If I call RealImportFromDB(...)

因为该方法不适用于异步调用,所以它不会返回 TaskTask<T> ,这是进行异步调用的常见要求

您的代码,await RealImportFromDB(parent, child)不正确,这是一个编译错误,因为您只能等待实现 GetAwaiter() 的调用内部检查( thisthis ),最常见的情况是返回 TaskTask<T> , 还有其他类型

让我们尝试理解您的两个陈述:

1) For CPU-bound code, you await an operation which is started on a background thread with the Task.Run method. Such as calculating prime numbers

这是你目前正在做的,通常在客户端做,以释放 Ui 线程,而处理在后台进行,但这仍然会使用线程池线程来执行,这不如 Ui 重要线程,但仍然是系统资源

2) For I/O-bound code, you await an operation which returns a Task or Task inside of an async method. Such as waiting for network or database

要实现这一点,您需要一个方法,该方法默认为 Async 并返回一个 Task。或 Task<T> ,这样的方法是所有数据框架的一部分,对于现在的每个同步方法都有一个相应的异步方法来启动异步执行,它们是真正的 IO 调用,它们不使用线程,因为处理不在同一个进程,它跨越网络/进程边界,所以调用线程不需要等待,它只需要在结果到达时返回并选择结果(任何线程池线程,不需要调度线程)。在内部,此类方法使用 TaskCompletionSource<T> ( When to use TaskCompletionSource ),它具有在网络调用完成时通知调用者的机制

关于C# 了解阻塞 UI 和异步/等待与 Task.Run 的麻烦?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52343825/

相关文章:

c# - 使用条件运算符?避免 if 条件

c# - 尝试了解 "Common"与 ASP.NET 和 HttpClient() 的异步死锁

c# - Mono 上的简单 HttpClient 测试失败

node.js - 尝试了解 Await/Async,这是正确的转换吗?

c# - CSVHelper 将值传递给 MapClass

c# - 连接池-一个进程-多个线程

c# - 从父窗体打开文件到子窗体的文本框 C#

java - 从数据库提取数据时如何与 "future"同步

java - 使用适用于 Java 的 AWS 开发工具包版本 2 将 InputStream 异步(非阻塞)上传到 AWS s3

javascript - 我怎样才能让底部的 console.log 等到它全部完成,然后告诉我答案而不是等待?