ser*_*raj 4 c# wpf asynchronous async-await .net-core-3.1
这是我的代码。读取文件行的 WPF 按钮的事件处理程序:
private async void Button_OnClick(object sender, RoutedEventArgs e)
{
Button.Content = "Loading...";
var lines = await File.ReadAllLinesAsync(@"D:\temp.txt"); //Why blocking UI Thread???
Button.Content = "Show"; //Reset Button text
}
Run Code Online (Sandbox Code Playgroud)
我File.ReadAllLines()在 .NET Core 3.1 WPF App 中使用了异步版本的方法。
但它阻塞了 UI 线程!为什么?
更新:与@Theodor Zoulias 相同,我做了一个测试:
private async void Button_OnClick(object sender, RoutedEventArgs e)
{
Button.Content = "Loading...";
TextBox.Text = "";
var stopwatch = Stopwatch.StartNew();
var task = File.ReadAllLinesAsync(@"D:\temp.txt"); //Problem
var duration1 = stopwatch.ElapsedMilliseconds;
var isCompleted = task.IsCompleted;
stopwatch.Restart();
var lines = await task;
var duration2 = stopwatch.ElapsedMilliseconds;
Debug.WriteLine($"Create: {duration1:#,0} msec, Task.IsCompleted: {isCompleted}");
Debug.WriteLine($"Await: {duration2:#,0} msec, Lines: {lines.Length:#,0}");
Button.Content = "Show";
}
Run Code Online (Sandbox Code Playgroud)
结果是:
Create: 652 msec msec, Task.IsCompleted: False | Await: 15 msec, Lines: 480,001
Run Code Online (Sandbox Code Playgroud)
.NET Core 3.1、C# 8、WPF、调试构建 | 7.32 Mb 文件(.txt) | 硬盘 5400 SATA
遗憾的是,根据 Microsoft自己关于异步方法预期行为的建议,用于访问文件系统的内置异步 API 并未一致实现。
基于 TAP 的异步方法可以在返回结果任务之前同步执行少量工作,例如验证参数和启动异步操作。同步工作应该保持在最低限度,以便异步方法可以快速返回。
像StreamReader.ReadToEndAsync这样的方法不会以这种方式运行,而是在返回一个不完整的Task. 例如,在我从 SSD 读取 6MB 文件的旧实验中,此方法将调用线程阻塞了 120 毫秒,Task然后返回一个仅在 20 毫秒后完成的。我的建议是避免使用 GUI 应用程序中的异步文件系统 API,而是使用Task.Run.
var lines = await Task.Run(() => File.ReadAllLines(@"D:\temp.txt"));
Run Code Online (Sandbox Code Playgroud)
更新:以下是一些实验结果File.ReadAllLinesAsync:
var stopwatch = Stopwatch.StartNew();
var task = File.ReadAllLinesAsync(@"C:\6MBfile.txt");
var duration1 = stopwatch.ElapsedMilliseconds;
bool isCompleted = task.IsCompleted;
stopwatch.Restart();
var lines = await task;
var duration2 = stopwatch.ElapsedMilliseconds;
Console.WriteLine($"Create: {duration1:#,0} msec, Task.IsCompleted: {isCompleted}");
Console.WriteLine($"Await: {duration2:#,0} msec, Lines: {lines.Length:#,0}");
Run Code Online (Sandbox Code Playgroud)
输出:
var lines = await Task.Run(() => File.ReadAllLines(@"D:\temp.txt"));
Run Code Online (Sandbox Code Playgroud)
该方法File.ReadAllLinesAsync阻塞当前线程450毫秒,5毫秒后返回的任务完成。这些测量在多次运行后是一致的。
.NET Core 3.1.3、C# 8、控制台应用程序、发布版本(未附加调试器)、Windows 10、SSD Toshiba OCZ Arc 100 240GB
| 归档时间: |
|
| 查看次数: |
620 次 |
| 最近记录: |